You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2020/05/01 06:05:59 UTC
[mina-sshd] branch master updated: [SSHD-987] Correctly generate IV
for AES private key obfuscator
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push:
new 742963a [SSHD-987] Correctly generate IV for AES private key obfuscator
742963a is described below
commit 742963a5cdff42361c7b372e3fd7ad11d7046f67
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Wed Apr 29 19:09:37 2020 +0300
[SSHD-987] Correctly generate IV for AES private key obfuscator
---
.../keys/loader/AESPrivateKeyObfuscator.java | 29 +++++++++++++++++
.../keys/loader/AbstractPrivateKeyObfuscator.java | 19 ++++-------
.../keys/loader/DESPrivateKeyObfuscator.java | 4 +--
.../keys/loader/AESPrivateKeyObfuscatorTest.java | 38 ++++++++++++++++++----
4 files changed, 69 insertions(+), 21 deletions(-)
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscator.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscator.java
index d45391d..8ba47ce 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscator.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscator.java
@@ -21,14 +21,18 @@ package org.apache.sshd.common.config.keys.loader;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.Key;
+import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Predicate;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.CipherInformation;
import org.apache.sshd.common.util.security.SecurityUtils;
/**
@@ -57,6 +61,24 @@ public class AESPrivateKeyObfuscator extends AbstractPrivateKeyObfuscator {
}
@Override
+ protected int resolveInitializationVectorLength(PrivateKeyEncryptionContext encContext) throws GeneralSecurityException {
+ int keyLength = resolveKeyLength(encContext);
+ CipherInformation ci = resolveCipherInformation(keyLength, encContext.getCipherMode());
+ if (ci == null) {
+ throw new NoSuchAlgorithmException("No match found for " + encContext);
+ }
+ return ci.getIVSize();
+ }
+
+ protected CipherInformation resolveCipherInformation(int keyLength, String cipherMode) {
+ Predicate<CipherInformation> selector = createCipherSelector(keyLength, cipherMode);
+ return BuiltinCiphers.VALUES.stream()
+ .filter(selector)
+ .findFirst()
+ .orElse(null);
+ }
+
+ @Override
protected int resolveKeyLength(PrivateKeyEncryptionContext encContext) throws GeneralSecurityException {
String cipherType = encContext.getCipherType();
try {
@@ -87,6 +109,13 @@ public class AESPrivateKeyObfuscator extends AbstractPrivateKeyObfuscator {
return LazyKeyLengthsHolder.KEY_LENGTHS;
}
+ public static Predicate<CipherInformation> createCipherSelector(int keyLength, String cipherMode) {
+ String xformMode = "/" + cipherMode.toUpperCase() + "/";
+ return c -> CIPHER_NAME.equalsIgnoreCase(c.getAlgorithm())
+ && (keyLength == c.getKeySize())
+ && c.getTransformation().contains(xformMode);
+ }
+
private static final class LazyKeyLengthsHolder {
private static final List<Integer> KEY_LENGTHS = Collections.unmodifiableList(detectSupportedKeySizes());
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractPrivateKeyObfuscator.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractPrivateKeyObfuscator.java
index cc6d300..57ff3e3 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractPrivateKeyObfuscator.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/AbstractPrivateKeyObfuscator.java
@@ -57,7 +57,11 @@ public abstract class AbstractPrivateKeyObfuscator implements PrivateKeyObfuscat
@Override
public byte[] generateInitializationVector(PrivateKeyEncryptionContext encContext)
throws GeneralSecurityException {
- return generateInitializationVector(resolveKeyLength(encContext));
+ int ivSize = resolveInitializationVectorLength(encContext);
+ byte[] initVector = new byte[ivSize];
+ Random randomizer = new SecureRandom(); // TODO consider using some pre-created singleton instance
+ randomizer.nextBytes(initVector);
+ return initVector;
}
@Override
@@ -80,17 +84,8 @@ public abstract class AbstractPrivateKeyObfuscator implements PrivateKeyObfuscat
return sb;
}
- protected byte[] generateInitializationVector(int keyLength) {
- int keySize = keyLength / Byte.SIZE;
- if ((keyLength % Byte.SIZE) != 0) { // e.g., if 36-bits then we need 5 bytes to hold
- keySize++;
- }
-
- byte[] initVector = new byte[keySize];
- Random randomizer = new SecureRandom(); // TODO consider using some pre-created singleton instance
- randomizer.nextBytes(initVector);
- return initVector;
- }
+ protected abstract int resolveInitializationVectorLength(PrivateKeyEncryptionContext encContext)
+ throws GeneralSecurityException;
protected abstract int resolveKeyLength(PrivateKeyEncryptionContext encContext) throws GeneralSecurityException;
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/DESPrivateKeyObfuscator.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/DESPrivateKeyObfuscator.java
index e62882b..411ca85 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/DESPrivateKeyObfuscator.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/DESPrivateKeyObfuscator.java
@@ -57,8 +57,8 @@ public class DESPrivateKeyObfuscator extends AbstractPrivateKeyObfuscator {
}
@Override
- protected byte[] generateInitializationVector(int keyLength) {
- return super.generateInitializationVector(8 * Byte.SIZE);
+ protected int resolveInitializationVectorLength(PrivateKeyEncryptionContext encContext) throws GeneralSecurityException {
+ return 8;
}
public static final PrivateKeyEncryptionContext resolveEffectiveContext(PrivateKeyEncryptionContext encContext) {
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java
index 46daf15..df0c7f7 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java
@@ -20,12 +20,16 @@ package org.apache.sshd.common.config.keys.loader;
import java.security.GeneralSecurityException;
import java.security.Key;
+import java.util.Collection;
import java.util.List;
-import java.util.Random;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.CipherInformation;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.security.SecurityUtils;
import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
@@ -48,8 +52,6 @@ import org.junit.runners.Parameterized.UseParametersRunnerFactory;
@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
@Category({ NoIoTestCase.class })
public class AESPrivateKeyObfuscatorTest extends JUnitTestSupport {
- private static final Random RANDOMIZER = new Random(System.currentTimeMillis());
-
private final int keyLength;
public AESPrivateKeyObfuscatorTest(int keyLength) {
@@ -67,13 +69,35 @@ public class AESPrivateKeyObfuscatorTest extends JUnitTestSupport {
public void testAvailableKeyLengthExists() throws GeneralSecurityException {
assertEquals("Not a BYTE size multiple", 0, keyLength % Byte.SIZE);
- byte[] iv = new byte[keyLength / Byte.SIZE];
- synchronized (RANDOMIZER) {
- RANDOMIZER.nextBytes(iv);
- }
+ PrivateKeyEncryptionContext encContext = new PrivateKeyEncryptionContext();
+ encContext.setCipherName(AESPrivateKeyObfuscator.CIPHER_NAME);
+ encContext.setCipherMode(PrivateKeyEncryptionContext.DEFAULT_CIPHER_MODE);
+ encContext.setCipherType(Integer.toString(keyLength));
+
+ int actual = AESPrivateKeyObfuscator.INSTANCE.resolveKeyLength(encContext);
+ assertEquals("Mismatched resolved key length", keyLength, actual);
+
+ // see SSHD-987
+ byte[] iv = AESPrivateKeyObfuscator.INSTANCE.generateInitializationVector(encContext);
+ assertEquals("Mismatched IV size", 16 /* TODO change this if GCM allowed */, iv.length);
Key key = new SecretKeySpec(iv, AESPrivateKeyObfuscator.CIPHER_NAME);
Cipher c = SecurityUtils.getCipher(AESPrivateKeyObfuscator.CIPHER_NAME);
c.init(Cipher.DECRYPT_MODE, key);
}
+
+ @Test
+ public void testSingleCipherMatch() {
+ Predicate<CipherInformation> selector = AESPrivateKeyObfuscator.createCipherSelector(
+ keyLength, PrivateKeyEncryptionContext.DEFAULT_CIPHER_MODE);
+ Collection<CipherInformation> matches = BuiltinCiphers.VALUES.stream()
+ .filter(selector)
+ .collect(Collectors.toList());
+ assertEquals("Mismatched matching ciphers: " + matches, 1, GenericUtils.size(matches));
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[keyLength=" + keyLength + "]";
+ }
}