如何列出可用的加密算法?

50

我正在使用 Cipher.getInstance(String algorithm) 获取Cipher实现。 我的理解是,我可以传递的可用算法名称取决于我的类路径中存在哪些库。

我想编写一个简单的程序,在不同的类路径下运行该程序,列出可用的Cipher算法名称。我需要调用什么方法来获取此列表?


3
Security.getAlgorithms("Cipher") 这个方法不能满足你的需求吗? - David Moles
5个回答

38

在 JB Nizet 的帖子中描述的方式中,一旦我有了提供者列表,我仍然没有算法列表。我发现每个提供者都作为一个属性对象来运行,并且这些属性编码了算法名称。我不完全清楚这是否是查找它们的正确方式以及所有其他属性的确切含义,但我编写了一个例程将所有属性输出到 System.out 并使用各种描述我正在寻找的字符串进行检索,直到找到它。

import java.security.*;

for (Provider provider: Security.getProviders()) {
  System.out.println(provider.getName());
  for (String key: provider.stringPropertyNames())
    System.out.println("\t" + key + "\t" + provider.getProperty(key));
}

2
是的,我使用相同的方法,但使用正则表达式在多个提供程序中寻找算法。大多数情况下最好查看列表,因为文档可能已过时(或在许多情况下为空)。棘手的问题当然是要知道算法实际上是什么,因为任何地方都没有提供解释。请注意,有许多“别名”,如果您只是检查是否已实现算法,则可能需要从列表中删除它们。 - Maarten Bodewes

32

要获取可用的加密转换名称列表,请使用此代码片段:

Set<String> algs = new TreeSet<>();
for (Provider provider : Security.getProviders()) {
    provider.getServices().stream()
                          .filter(s -> "Cipher".equals(s.getType()))
                          .map(Service::getAlgorithm)
                          .forEach(algs::add);
}
algs.forEach(System.out::println);

这些名称可以通过 Cipher.getInstance() 进行调用。如果缺少反馈模式或填充方案,则 JVM 将回退到相应的默认设置。

AES
AESWrap
AESWrap_128
AESWrap_192
AESWrap_256
AES_128/CBC/NoPadding
AES_128/CFB/NoPadding
AES_128/ECB/NoPadding
AES_128/GCM/NoPadding
AES_128/OFB/NoPadding
AES_192/CBC/NoPadding
AES_192/CFB/NoPadding
AES_192/ECB/NoPadding
AES_192/GCM/NoPadding
AES_192/OFB/NoPadding
AES_256/CBC/NoPadding
AES_256/CFB/NoPadding
AES_256/ECB/NoPadding
AES_256/GCM/NoPadding
AES_256/OFB/NoPadding
ARCFOUR
Blowfish
ChaCha20
ChaCha20-Poly1305
DES
DESede
DESedeWrap
PBEWithHmacSHA1AndAES_128
PBEWithHmacSHA1AndAES_256
PBEWithHmacSHA224AndAES_128
PBEWithHmacSHA224AndAES_256
PBEWithHmacSHA256AndAES_128
PBEWithHmacSHA256AndAES_256
PBEWithHmacSHA384AndAES_128
PBEWithHmacSHA384AndAES_256
PBEWithHmacSHA512AndAES_128
PBEWithHmacSHA512AndAES_256
PBEWithMD5AndDES
PBEWithMD5AndTripleDES
PBEWithSHA1AndDESede
PBEWithSHA1AndRC2_128
PBEWithSHA1AndRC2_40
PBEWithSHA1AndRC4_128
PBEWithSHA1AndRC4_40
RC2
RSA
RSA/ECB/PKCS1Padding

另请参阅JDK文档中的密码算法名称

要获取可用的TLS密码套件列表,请使用此一行命令:

$ jrunscript -e "java.util.Arrays.asList(javax.net.ssl.SSLServerSocketFactory.getDefault().getSupportedCipherSuites()).stream().forEach(println)"

JDK11的输出结果如下:

TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA

你确定这些算法是Cipher.getInstance(String algorithm)中所要求的吗?我得到了几乎相同的结果,但如果我使用任何一个打印出来的名称,我会得到java.security.NoSuchAlgorithmException: Cannot find any provider supporting TLS_AES_128_GCM_SHA256错误 - 也许可以尝试使用类似jrunscript -e println(java.security.Security.getAlgorithms(\"Cipher\"))的方式。 - user85421
@CarlosHeuberger 你说得对。我混淆了“Cipher”和“Cipher Suites”这两个术语。上面的命令列出了特定TLS版本可以使用的所有“Cipher Suites”。但是作者要求实现特定转换的“Ciphers”。 一个转换由名称、模式和填充组成。例如,您可以使用Cipher.getInstance("AES/GCM/NoPadding")获得AES GCM密码。 - Rod Rob
哈,具有讽刺意味的是,动态拉取密码套件正是我一直在寻找的,以便跟踪在后续的Java更新中添加/删除的内容,这些内容并没有单独记录。 - galaxis

23

Cipher.getInstance()的文档表示:

请注意,已注册提供程序的列表可以通过Security.getProviders()方法检索

点击链接跳转到Provider的文档页面,该页面有一个名为getServices()的方法,其说明为:

获取此提供程序支持的所有服务的不可修改集合。

点击链接跳转到Provider的文档页面,该页面有一个名为getAlgorithm()的方法。

请注意,这是一种非常经验主义的方法。更合理的方法是阅读您正在使用的加密库的文档。它必须包含支持的算法列表。

无论您选择哪种方法,阅读文档都会帮助很多。


谢谢。当我阅读文档时,我完全忽视了关于 Security.getProviders() 的注释,我对为什么里面似乎没有任何内容感到困惑。 - skiphoppy

5

2
这是基于Atlassian的说明撰写的版本:
  • To include a cipher suite or protocol you require that is not enabled by default.
  • To exclude a cipher suite or protocol that is considered too weak to use, or for which a vulnerability has been discovered.

    import java.util.Map;
    import java.util.TreeMap;
    
    import javax.net.ssl.SSLServerSocketFactory;
    
    public class Ciphers {
    
    public static void main(String[] args) {
        SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
    
        String[] defaultCiphers = ssf.getDefaultCipherSuites();
        String[] availableCiphers = ssf.getSupportedCipherSuites();
    
        Map<String, Boolean> ciphers = new TreeMap<>();
    
        for (String availableCipher : availableCiphers) {
            ciphers.put(availableCipher, Boolean.FALSE);
        }
    
        for (String defaultCipher : defaultCiphers) {
            ciphers.put(defaultCipher, Boolean.TRUE);
        }
    
        System.out.println("Default\tCipher");
        for (Map.Entry<String, Boolean> cipher : ciphers.entrySet()) {
            if (Boolean.TRUE.equals(cipher.getValue())) {
                System.out.print('*');
            } else {
                System.out.print(' ');
            }
    
            System.out.print('\t');
            System.out.println(cipher.getKey());
        }
    }
    }
    

输出:

默认密码

  • TLS_DHE_DSS_WITH_AES_128_CBC_SHA
  • TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
  • TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
  • TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
  • TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
  • TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
  • TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
  • TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
  • TLS_RSA_WITH_AES_128_CBC_SHA
  • TLS_RSA_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_AES_128_GCM_SHA256
  • TLS_RSA_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_RSA_WITH_AES_256_GCM_SHA384

不是算法,而是尝试使用Cipher.getInstance(String algorithm)返回一些结果,正如问题所要求的那样 - 结果是NoSuchAlgorithmException(密码套件!=算法?) - user85421
在Cipher.getInstance(String algorithm)中,algorithm是转换的名称而不是密码算法的名称。因此,获取NoSuchAlgorithmException是正确的。您需要找到的是受支持的转换集合。 - Tom Rutchik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接