Skip to content

Commit

Permalink
hadoop-crypto no longer depends on commons-crypto or openssl
Browse files Browse the repository at this point in the history
  • Loading branch information
carterkozak committed Nov 9, 2021
1 parent 29147be commit 7dc6bdd
Show file tree
Hide file tree
Showing 13 changed files with 20 additions and 376 deletions.
41 changes: 0 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,44 +187,3 @@ Hadoop Configuration Properties
License
-------
This repository is made available under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).


FAQ
---

## log.warn lines from `CryptoStreamFactory`

`WARN: Unable to initialize cipher with OpenSSL, falling back to JCE implementation`

'Falling back to the JCE implementation' results in slower cipher performance than native OpenSSL. Resolve this by installing a compatible OpenSSL and symlinking it to the correct location, `/usr/lib/libcrypto.so`. (OpenSSL 1.0 and 1.1 are currently supported)

_Note: to support OpenSSL 1.1, we use releases from the [Palantir fork of commons-crypto](https://github.com/palantir/commons-crypto/releases) as support has been added to the mainline Apache repo, but no release made [since 2016](https://github.com/apache/commons-crypto/releases)._

```
Exception in thread "main" java.io.IOException: java.security.GeneralSecurityException: CryptoCipher {org.apache.commons.crypto.cipher.OpenSslCipher} is not available or transformation AES/CTR/NoPadding is not supported.
at org.apache.commons.crypto.utils.Utils.getCipherInstance(Utils.java:130)
at ApacheCommonsCryptoLoad.main(ApacheCommonsCryptoLoad.java:10)
Caused by: java.security.GeneralSecurityException: CryptoCipher {org.apache.commons.crypto.cipher.OpenSslCipher} is not available or transformation AES/CTR/NoPadding is not supported.
at org.apache.commons.crypto.cipher.CryptoCipherFactory.getCryptoCipher(CryptoCipherFactory.java:176)
at org.apache.commons.crypto.utils.Utils.getCipherInstance(Utils.java:128)
... 1 more
Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at org.apache.commons.crypto.utils.ReflectionUtils.newInstance(ReflectionUtils.java:90)
at org.apache.commons.crypto.cipher.CryptoCipherFactory.getCryptoCipher(CryptoCipherFactory.java:160)
... 2 more
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.apache.commons.crypto.utils.ReflectionUtils.newInstance(ReflectionUtils.java:88)
... 3 more
Caused by: java.lang.RuntimeException: java.lang.UnsatisfiedLinkError: EVP_CIPHER_CTX_cleanup
at org.apache.commons.crypto.cipher.OpenSslCipher.<init>(OpenSslCipher.java:59)
... 8 more
Caused by: java.lang.UnsatisfiedLinkError: EVP_CIPHER_CTX_cleanup
at org.apache.commons.crypto.cipher.OpenSslNative.initIDs(Native Method)
at org.apache.commons.crypto.cipher.OpenSsl.<clinit>(OpenSsl.java:95)
at org.apache.commons.crypto.cipher.OpenSslCipher.<init>(OpenSslCipher.java:57)
... 8 more
```
4 changes: 0 additions & 4 deletions crypto-core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
apply from: "${rootDir}/gradle/openssl.gradle"

dependencies {
compile project(':crypto-keys')

compile "com.google.guava:guava"
compile "com.palantir.seek-io:seek-io"
compile "org.apache.commons:commons-crypto"
implementation "org.slf4j:slf4j-api"

annotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess'
compileOnly 'org.openjdk.jmh:jmh-generator-annprocess'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@
package com.palantir.crypto2.cipher;

import java.util.Properties;
import org.apache.commons.crypto.cipher.CryptoCipherFactory;

public final class ApacheCiphers {

private ApacheCiphers() {}

/**
* Configures the provided {@link Properties} such that {@link CryptoCipherFactory#getCryptoCipher(String,
* Properties)} will only try to use the OpenSSL cipher implementation which uses AES-NI.
* Does nothing.
*
* Previously configured the provided {@link Properties} such that
* {@code CryptoCipherFactory#getCryptoCipher(String, Properties)} will only try to use the OpenSSL cipher
* implementation which uses AES-NI.
*
* @deprecated Exists for abi compatibility, no longer does anything.
*/
@Deprecated
public static Properties forceOpenSsl(Properties properties) {
properties.setProperty(CryptoCipherFactory.CLASSES_KEY,
CryptoCipherFactory.CipherProvider.OPENSSL.getClassName());
return properties;
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package com.palantir.crypto2.io;

import com.google.common.annotations.VisibleForTesting;
import com.palantir.crypto2.cipher.ApacheCiphers;
import com.palantir.crypto2.cipher.SeekableCipher;
import com.palantir.crypto2.cipher.SeekableCipherFactory;
import com.palantir.crypto2.keys.KeyMaterial;
Expand All @@ -26,48 +24,19 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import org.apache.commons.crypto.stream.CtrCryptoOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class CryptoStreamFactory {

private static final Logger log = LoggerFactory.getLogger(CryptoStreamFactory.class);
private static final Properties PROPS = ApacheCiphers.forceOpenSsl(new Properties());
private static final String AES_ALGORITHM = "AES/CTR/NoPadding";
private static final String OPEN_SSL_INIT_WARNING = "Unable to initialize cipher with OpenSSL, falling back to "
+ "JCE implementation - see github.com/palantir/hadoop-crypto#faq";

private static volatile boolean fullExceptionLoggedAlready = false;

private CryptoStreamFactory() {}

/**
* Returns a {@link SeekableInput} that decrypts the given SeekableInput using the given {@link KeyMaterial} and
* cipher {@code algorithm}. When OpenSSL is available an implementation that uses AES-NI will be returned.
*/
public static SeekableInput decrypt(SeekableInput encryptedInput, KeyMaterial keyMaterial, String algorithm) {
return decrypt(encryptedInput, keyMaterial, algorithm, false);
}

@SuppressWarnings("CatchBlockLogException")
@VisibleForTesting
static SeekableInput decrypt(
SeekableInput encryptedInput, KeyMaterial keyMaterial, String algorithm, boolean forceJce) {
if (!algorithm.equals(AES_ALGORITHM) || forceJce) {
return new DecryptingSeekableInput(encryptedInput, SeekableCipherFactory.getCipher(algorithm, keyMaterial));
}

try {
return new ApacheCtrDecryptingSeekableInput(encryptedInput, keyMaterial);
} catch (IOException e) {
warningLog(e);
return new DecryptingSeekableInput(encryptedInput, SeekableCipherFactory.getCipher(algorithm, keyMaterial));
}
return new DecryptingSeekableInput(encryptedInput, SeekableCipherFactory.getCipher(algorithm, keyMaterial));
}

/**
Expand All @@ -83,39 +52,7 @@ public static InputStream decrypt(InputStream input, KeyMaterial keyMaterial, St
* cipher {@code algorithm}. When OpenSSL is available an implementation that uses AES-NI will be returned.
*/
public static OutputStream encrypt(OutputStream output, KeyMaterial keyMaterial, String algorithm) {
return encrypt(output, keyMaterial, algorithm, false);
}

@SuppressWarnings("CatchBlockLogException")
@VisibleForTesting
static OutputStream encrypt(OutputStream output, KeyMaterial keyMaterial, String algorithm, boolean forceJce) {
if (!algorithm.equals(AES_ALGORITHM) || forceJce) {
return createDefaultEncryptedStream(output, keyMaterial, algorithm);
}

try {
return createApacheEncryptedStream(output, keyMaterial);
} catch (IOException e) {
warningLog(e);
return createDefaultEncryptedStream(output, keyMaterial, algorithm);
}
}

/** To avoid spamming logs with exceptions, we only log the exception once. */
private static void warningLog(IOException exception) {
if (fullExceptionLoggedAlready) {
log.warn(OPEN_SSL_INIT_WARNING);
} else {
log.warn(OPEN_SSL_INIT_WARNING, exception);
fullExceptionLoggedAlready = true;
}
}

private static OutputStream createApacheEncryptedStream(OutputStream output, KeyMaterial keyMaterial)
throws IOException {
SecretKey secretKey = keyMaterial.getSecretKey();
byte[] iv = keyMaterial.getIv();
return new CtrCryptoOutputStream(PROPS, output, secretKey.getEncoded(), iv);
return createDefaultEncryptedStream(output, keyMaterial, algorithm);
}

private static OutputStream createDefaultEncryptedStream(OutputStream output, KeyMaterial keyMaterial,
Expand Down

This file was deleted.

Loading

0 comments on commit 7dc6bdd

Please sign in to comment.