【问题标题】:How to check if Cipher supports certain key size?如何检查 Cipher 是否支持特定的密钥大小?
【发布时间】:2017-01-07 23:35:50
【问题描述】:

如何检查所选密码算法转换是否支持特定的密钥长度?

boolean checkAlgorithm( String encryptMethod, int keyLength ) {
  Cipher cipher = Cipher.getInstance(encryptMethod);
  int maxLength = cipher.getMaxAllowedKeyLength(encryptMethod); 

  if ( keyLength <= maxLength && SOMETHING_ELSE ) { 
    return true;
  } else {
    return false;
  }

}

有没有一种方法,无需对每个转换逐个进行,例如:

switch( encryptMethod ) {
  case "Blowfish":
    if ( keyLength <= maxLength && keyLength >= 32 && keyLength % 8 == 0 ) {
    }
    ...
}

【问题讨论】:

    标签: java encryption key


    【解决方案1】:

    是的,您当然可以循环浏览它们,但 Java 没有属性(就像 C#/.NET 一样,可以返回密码“服务”的所有可能的密钥大小。

    由于密钥大小通常由标准定义(例如 AES 和所有 AES 候选者的 128、192 和 256 位),因此在您的应用程序代码中使它们成为常量相对容易。

    通常,无论如何您都不想动态设置密钥大小。但是,是的,您无法获取此信息很烦人(现在添加它可能会破坏所有提供程序的实现)。


    getMaxAllowedKeyLength 不应用于此目的。安装无限制加密扩展时(对于此特定运行时),它将返回 Integer.MAX_VALUE。注意,它是一个静态方法,所以从对象实例调用它也是不对的,在需要的地方使用Cipher.getMaxAllowedKeyLength即可。

    如果您想知道,您可以简单地尝试对称密码从 16 到 32 或 64 字节的所有密钥大小。 Cipher 类本身列出了必须支持的密码密钥大小(一直到底部)。


    好的,如果你确实想试试这个:

    package nl.owlstead.stackoverflow;
    
    import java.security.NoSuchAlgorithmException;
    import java.security.Provider;
    import java.security.Provider.Service;
    import java.security.Security;
    import java.util.Set;
    import java.util.SortedSet;
    import java.util.TreeSet;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    public class FindKeySizes {
    
        public static void main(String[] args) throws Exception {
            Security.addProvider(new BouncyCastleProvider());
            Provider[] providers = Security.getProviders();
            for (Provider provider : providers) {
                Set<Service> services = provider.getServices();
                for (Service service : services) {
                    if (!service.getType().equalsIgnoreCase("cipher")) {
                        continue;
                    }
    
                    String alg = service.getAlgorithm();
    
                    KeyGenerator skf = null;
                    Cipher cipher;
                    try {
                        // filters out symmetric algorithms
                        skf = KeyGenerator.getInstance(alg, provider);
                    } catch (NoSuchAlgorithmException e) {
                        // OK, that may not exist
                    }
                    try {
                        cipher = Cipher.getInstance(alg, provider);
                    } catch (NoSuchAlgorithmException e) {
                        continue;
                    }
    
                    SortedSet<Integer> keySizes = new TreeSet<>();
                    for (int keySize = Byte.SIZE; keySize <= 512; keySize += Byte.SIZE) {
                        try {
                            SecretKey key;
                            if (skf != null) {
                                try {
                                    skf.init(keySize);
                                    key = skf.generateKey();
                                } catch (Exception e) {
                                    continue;
                                }
                            } else {
                                key = new SecretKeySpec(new byte[keySize / Byte.SIZE], alg);
                            }
                            cipher.init(Cipher.ENCRYPT_MODE, key);
                            keySizes.add(keySize);
                        } catch (Exception e) {
                            // needed for RuntimeException from providers
                            if (alg.equalsIgnoreCase("AES") && (keySize == 128)) {
                                e.printStackTrace(System.err);
                            }
    
                            continue;
                        }
                    }
    
                    if (!keySizes.isEmpty()) {
                        System.out.printf("Provider: %s, cipher: %s, key sizes: %s%n",
                                provider.getName(), alg, keySizes);
                    }
                }
            }
        }
    }
    

    应该可以解决问题。结果比我想的要丑。

    【讨论】:

    • 感谢您的回复。我真的很难过这是不可能的。无论如何,我做的非常相似,但方式不同。我只是将密钥(可能支持密码)传递给密码并检查异常,如果没有人被抛出,这意味着密钥是有效的。
    • 请注意,有许多密码可以接受 8 位增量的非常高和非常低的密钥大小。这给出了一个想法,如果您以某种方式尝试使用动态密钥大小会发生什么。通常,您使用一个算法/密钥大小参数或在您的协议/应用程序中创建一组具有相应密钥大小的算法。
    • 我实际上正在开发一个加密工具,我希望用户可以在其中定义自己的算法,该方法应该检查用户输入是否有效。也许我应该生成参数长度的密钥并尝试加密指定的字符串(例如“Test”)然后检查新字符串是否等于(“Test”)如果不存在,算法存在..只是想......
    • 要使用 Cipher,您必须创建一个签名的提供者。所以你最好还是使用自己的 API(或者 Bouncy Castle 轻量级 API,而不是包含这个功能的 API)。
    • 您需要自己创建私钥并从 Oracle (!) 获取证书。这可能需要几个月的时间。如果他们决定给你一个...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    • 2018-06-09
    • 2020-12-01
    • 1970-01-01
    • 2016-07-22
    相关资源
    最近更新 更多