Skip to content

JRuby cannot decrypt a private key using the AES-256-CBC cipher #919

Closed
drbrain opened this Issue Jul 25, 2013 · 10 comments

6 participants

@drbrain
drbrain commented Jul 25, 2013

JRuby should be able to decrypt keys using the same ciphers as Ruby, but fails for several common ciphers including AES-256-CBC.

While this script does not have proper setup for some of the ciphers (notably ECB mode), in general it shows which cipher families do and do not work on JRuby:

require 'openssl'

# https://bugs.ruby-lang.org/issues/8690
exclude = %w[
  AES-128-CBC-HMAC-SHA1
  AES-256-CBC-HMAC-SHA1
  aes-128-cbc-hmac-sha1
  aes-256-cbc-hmac-sha1
]

key = OpenSSL::PKey::RSA.new 1024

OpenSSL::Cipher.ciphers.each do |cipher_name|
  begin
    next if exclude.include? cipher_name

    print cipher_name

    cipher = OpenSSL::Cipher.new cipher_name
    encryption_key = cipher.random_key

    encrypted = key.export cipher, encryption_key

    OpenSSL::PKey::RSA.new encrypted, encryption_key

    puts " PASS"
  rescue
    puts " FAIL: #{$!}"
  end
end

My results with jruby 1.7.4 (1.9.3p392) 2013-05-16 2390d3b on Java HotSpot(TM) 64-Bit Server VM 1.7.0_10-ea-b16 [darwin-x86_64] for the AES ciphers:

$ jruby test.rb | grep AES
Unable to find a $JAVA_HOME at "/usr", continuing with system-provided Java...
AES-128 PASS
AES-128-CBC PASS
AES-128-CFB PASS
AES-128-CFB1 PASS
AES-128-CFB8 FAIL: Neither PUB key nor PRIV key:
AES-128-ECB FAIL: exception using cipher: java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
AES-128-OFB PASS
AES-192 FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-192-CBC FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-192-CFB FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-192-CFB1 FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-192-CFB8 FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-192-ECB FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-192-OFB FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-256 FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-256-CBC FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-256-CFB FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-256-CFB1 FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-256-CFB8 FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-256-ECB FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size
AES-256-OFB FAIL: exception using cipher: java.security.InvalidKeyException: Illegal key size

With ruby 2.0.0p247:

$ ruby test.rb | grep AES
AES-128-CBC PASS
AES-128-CFB PASS
AES-128-CFB1 PASS
AES-128-CFB8 PASS
AES-128-CTR PASS
AES-128-ECB FAIL: Neither PUB key nor PRIV key: nested asn1 error
AES-128-OFB PASS
AES-128-XTS PASS
AES-192-CBC PASS
AES-192-CFB PASS
AES-192-CFB1 PASS
AES-192-CFB8 PASS
AES-192-CTR PASS
AES-192-ECB FAIL: Neither PUB key nor PRIV key: nested asn1 error
AES-192-OFB PASS
AES-256-CBC PASS
AES-256-CFB PASS
AES-256-CFB1 PASS
AES-256-CFB8 PASS
AES-256-CTR PASS
AES-256-ECB FAIL: Neither PUB key nor PRIV key: nested asn1 error
AES-256-OFB PASS
AES-256-XTS PASS
AES128 PASS
AES192 PASS
AES256 PASS
@drbrain drbrain added a commit to rubygems/rubygems that referenced this issue Jul 25, 2013
@drbrain drbrain Encrypt test key with DES-CBC for JRuby
AES-256-CBC does not work for encrypting a key on JRuby, see jruby/jruby#919

Part of #606
ca228b7
@drbrain
drbrain commented Jul 25, 2013

Installing the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files I see the AES-192 and AES-256 ciphers pass except for CFB8.

Thanks to sluukkonen1 on #jruby for pointing me in this direction.

If the ciphers don't work without the altered policy files perhaps JRuby should remove them from the ciphers list?

@sluukkonen

Alternatively, JRuby could at least print a warning message telling the user to install the JCE Unlimited files.

@nahi nahi was assigned Jul 26, 2013
@BanzaiMan
JRuby Team member

See also http://jira.codehaus.org/browse/JRUBY-7093. This directly impacts usefulness of Rails 4.

@BanzaiMan
JRuby Team member

http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions leads me to believe that this is a limitation imposed by JVM which we probably cannot overcome.

@headius
JRuby Team member
headius commented Sep 17, 2013

So I investigated this nonsense and it turns out to be even stupider than I thought. The "unlimited strength jurisdiction policy files" you download from Oracle contain nothing more than security policies enabling the use of higher-strength crypto.

Specifically, they replace the default_local.policy file from $JAVA_HOME/jre/lib/security/local_policy.jar:

// Some countries have import limits on crypto strength. This policy file
// is worldwide importable.

grant {
    permission javax.crypto.CryptoPermission "DES", 64;
    permission javax.crypto.CryptoPermission "DESede", *;
    permission javax.crypto.CryptoPermission "RC2", 128, 
                                     "javax.crypto.spec.RC2ParameterSpec", 128;
    permission javax.crypto.CryptoPermission "RC4", 128;
    permission javax.crypto.CryptoPermission "RC5", 128, 
          "javax.crypto.spec.RC5ParameterSpec", *, 12, *;
    permission javax.crypto.CryptoPermission "RSA", *;
    permission javax.crypto.CryptoPermission *, 128;
};

With one that looks the same as the already existing default_US_export.policy from from US_export_policy.jar in the same dir:

// Manufacturing policy file.
grant {
    // There is no restriction to any algorithms.
    permission javax.crypto.CryptoAllPermission; 
};

So it's actually possible, via a couple trivial commands, to "upgrade" a local JDK to support unlimited-strength crypto without doing the download.

Now here's where it gets slippery. Would we violate some stupid crypto export law by simply providing a gem you can install that rewrites the crypto policy jars? The fact that the limitation is imposed solely by configuration is pretty stupid.

@BanzaiMan
JRuby Team member

@headius I agree in principle that this is an arbitrary legal restriction rather than a technical one. At the same time, I argue that it is not in our best interest to do anything from our end. In the eyes of the law, I suspect that the end user taking a deliberate action to remove the restriction goes a long way.

As for printing a warning, unless we can precisely determine when to issue them, I don't think it is feasible to do it.

@mkristian
JRuby Team member
@headius
JRuby Team member
headius commented Sep 17, 2013

mkristian: Yes, probably can. See discussion on #jruby today or http://wiki.jruby.org/UnlimitedStrengthCrypto for a Ruby one-liner that disables the restriction.

@headius headius added a commit that referenced this issue Sep 17, 2013
@headius headius Better error when JCE unlimited crypto is not available.
Related to #919
Related to JRUBY-7093
41bb4be
@headius
JRuby Team member
headius commented Sep 17, 2013

@sluukkonen The commit above attempts to improve the error message to point at a new wiki page describing the fix: http://wiki.jruby.org/UnlimitedStrengthCrypto. Thanks for the idea.

@headius
JRuby Team member
headius commented Sep 17, 2013

JRuby 1.7.5 will have a better error message providing instructions on fixing this with either the JCE files or with a Java integration hack, and Rails should hopefully work around this in rails/rails#12256. Closing this for now.

@headius headius closed this Sep 17, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.