diff --git a/changelog/@unreleased/pr-636.v2.yml b/changelog/@unreleased/pr-636.v2.yml new file mode 100644 index 000000000..40960e881 --- /dev/null +++ b/changelog/@unreleased/pr-636.v2.yml @@ -0,0 +1,10 @@ +type: improvement +improvement: + description: |- + To avoid potential stream corruption, throw if JDK-8292158 may cause AES-CTR encryption corruption. + + Determine if JVM is impacted by JDK-8292158 which can corrupt AES-CTR encryption streams. This bug impacts JDKs up to 11.0.18, 15.0.10, 17.0.6, 19.0.2 and when running on CPUs with AVX-512 vectorized AES support. + + See https://bugs.openjdk.org/browse/JDK-8292158 introduced by https://bugs.openjdk.org/browse/JDK-8233741 + links: + - https://github.com/palantir/hadoop-crypto/pull/636 diff --git a/crypto-core/src/main/java/com/palantir/crypto2/cipher/CipherStreamSupplierImpl.java b/crypto-core/src/main/java/com/palantir/crypto2/cipher/CipherStreamSupplierImpl.java index 46d6671c5..cff4332bb 100644 --- a/crypto-core/src/main/java/com/palantir/crypto2/cipher/CipherStreamSupplierImpl.java +++ b/crypto-core/src/main/java/com/palantir/crypto2/cipher/CipherStreamSupplierImpl.java @@ -31,6 +31,9 @@ public CipherInputStream getInputStream(InputStream is, Cipher cipher) { @Override public CipherOutputStream getOutputStream(OutputStream os, Cipher cipher) { + if (Jdk8292158.isAffectedByJdkAesCtrCorruption(cipher.getAlgorithm())) { + throw Jdk8292158.cannotEncryptAesCtrSafely(); + } return new CipherOutputStream(os, cipher); } } diff --git a/crypto-core/src/main/java/com/palantir/crypto2/cipher/Jdk8292158.java b/crypto-core/src/main/java/com/palantir/crypto2/cipher/Jdk8292158.java new file mode 100644 index 000000000..fbd2a2013 --- /dev/null +++ b/crypto-core/src/main/java/com/palantir/crypto2/cipher/Jdk8292158.java @@ -0,0 +1,284 @@ +/* + * (c) Copyright 2022 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.crypto2.cipher; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Splitter; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.io.BaseEncoding; +import com.palantir.logsafe.Preconditions; +import com.palantir.logsafe.SafeArg; +import com.palantir.logsafe.UnsafeArg; +import com.palantir.logsafe.exceptions.SafeIllegalStateException; +import com.palantir.logsafe.logger.SafeLogger; +import com.palantir.logsafe.logger.SafeLoggerFactory; +import java.io.IOException; +import java.lang.ProcessHandle.Info; +import java.lang.Runtime.Version; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.security.NoSuchProviderException; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; +import java.util.stream.Stream; +import javax.annotation.Nullable; +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * Determine if JVM is impacted by https://bugs.openjdk.org/browse/JDK-8292158 which can corrupt AES-CTR encryption + * streams. This bug impacts JDKs up to 11.0.18, 15.0.10, 17.0.6, 19.0.2 and when running on CPUs with AVX-512 + * vectorized AES support. + */ +public final class Jdk8292158 { + private static final SafeLogger log = SafeLoggerFactory.get(Jdk8292158.class); + private static final ImmutableSet argsToDisableAesCtrIntrinsics = + ImmutableSet.of("-XX:UseAVX=2", "-XX:-UseAES", "-XX:-UseAESCTRIntrinsics", "-XX:-UseAESIntrinsics"); + + // see StubGenerator::generate_aes_stubs in + // https://github.com/openjdk/jdk/blob/master/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L160 + @VisibleForTesting + static final ImmutableSet jdk8292158ImpactedCpuFlags = + ImmutableSet.of("vaes", "avx512bw", "avx512vl", "vpclmulqdq"); + + private static final Supplier isAffectedByJdkAesCtrCorruption = + Suppliers.memoize(() -> isAffectedByJdkAesCtrCorruption( + Runtime.version(), architecture(), ProcessHandle.current().info())); + + private Jdk8292158() {} + + public static SafeIllegalStateException cannotEncryptAesCtrSafely() { + throw cannotEncryptAesCtrSafely( + Runtime.version(), + architecture(), + getJvmArgs(ProcessHandle.current().info())); + } + + private static SafeIllegalStateException cannotEncryptAesCtrSafely( + Version version, String architecture, ImmutableSet args) { + throw new SafeIllegalStateException( + "JVM and CPU architecture is affected by JDK-8292158." + + " Add JVM arguments `-XX:+UnlockDiagnosticVMOptions -XX:-UseAESCTRIntrinsics`" + + " to disable AES-CTR intrinsics until a fixed JVM is available.", + SafeArg.of("architecture", architecture), + SafeArg.of("version", version), + SafeArg.of("jvmArgs", args)); + } + + /** + * Determines if this JVM and CPU is affected by JDK-8292158 AES-CTR corruption. + * @param algorithm cipher algorithm + * @return false if this JVM and CPU is not affected by JDK-8292158 AES-CTR corruption + * @throws SafeIllegalStateException is this JVM and CPU is affected by JDK-8292158 AES-CTR corruption + */ + public static boolean isAffectedByJdkAesCtrCorruption(@Nullable String algorithm) { + return algorithm != null && algorithm.contains("AES/CTR") && isAffectedByJdkAesCtrCorruption.get(); + } + + @VisibleForTesting + static boolean isAffectedByJdkAesCtrCorruption(Version version, String architecture, Info info) { + BooleanSupplier cpuHasAvx512 = () -> hasVectorizedAesCpu(Paths.get("/proc/cpuinfo")); + return isAffectedByJdkAesCtrCorruption(version, architecture, info, cpuHasAvx512); + } + + @VisibleForTesting + @SuppressWarnings("checkstyle:CyclomaticComplexity") + static boolean isAffectedByJdkAesCtrCorruption( + Version version, String architecture, Info info, BooleanSupplier cpuHasAvx512) { + if (isAesCtrBroken()) { + return true; + } + int featureVersion = version.feature(); + if (featureVersion >= 20) { + // https://git.openjdk.org/jdk/commit/9d76ac8a4453bc51d9dca2ad6c60259cfb2c4203 in jdk-20+17 + return false; + } + if (featureVersion < 11) { + // introduced in JDK 14 for https://bugs.openjdk.org/browse/JDK-8233741 / + // https://github.com/openjdk/jdk/commit/a6649eb089e4c9beb8b7f654db454710b4c7ef4a + // backported to JDK 11.0.9 in + // https://github.com/openjdk/jdk11u/commit/68b8506ad817d97738735ef1f3acdead9fb6e222 + return false; + } + + // fixed versions + if (featureVersion == 11 && version.compareTo(Version.parse("11.0.18")) >= 0) { + // https://bugs.openjdk.org/browse/JDK-8295297 + return false; + } + if (featureVersion == 15 && version.compareTo(Version.parse("15.0.10")) >= 0) { + // https://bugs.openjdk.org/browse/JDK-8295781 + return false; + } + if (featureVersion == 17 && version.compareTo(Version.parse("17.0.6")) >= 0) { + // https://bugs.openjdk.org/browse/JDK-8295296 + return false; + } + if (featureVersion == 19 && version.compareTo(Version.parse("19.0.2")) >= 0) { + // https://bugs.openjdk.org/browse/JDK-8295905 + return false; + } + + if (!"amd64".equals(architecture) && !"x64".equals(architecture) && !"x86".equals(architecture)) { + if (log.isDebugEnabled()) { + log.debug( + "Architecture is not affected by JDK-8292158", + SafeArg.of("architecture", architecture), + SafeArg.of("version", version)); + } + return false; + } + + ImmutableSet jvmArgs = getJvmArgs(info); + if (cpuHasAvx512.getAsBoolean() + && argsToDisableAesCtrIntrinsics.stream().noneMatch(jvmArgs::contains)) { + throw cannotEncryptAesCtrSafely(version, architecture, jvmArgs); + } + + if (log.isDebugEnabled()) { + log.debug( + "JVM is not affected by JDK-8292158", + SafeArg.of("architecture", architecture), + SafeArg.of("version", version), + SafeArg.of("jvmArgs", jvmArgs), + SafeArg.of("cpuHasAvx512", cpuHasAvx512.getAsBoolean())); + } + return false; + } + + private static String architecture() { + return System.getProperty("os.arch"); + } + + private static ImmutableSet getJvmArgs(Info info) { + return info.arguments().stream() + .flatMap(Arrays::stream) + .filter(Objects::nonNull) + .map(String::trim) + .filter(arg -> arg.startsWith("-XX:")) + .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder())); + } + + @VisibleForTesting + static boolean hasVectorizedAesCpu(Path path) { + if (!Files.isReadable(path)) { + return false; + } + + try (Stream lines = Files.lines(path)) { + return hasVectorizedAesCpu(lines); + } catch (IOException e) { + return false; + } + } + + @VisibleForTesting + static boolean hasVectorizedAesCpu(Stream lines) { + // See https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX-512 + Splitter splitter = Splitter.onPattern("\\s+").trimResults().omitEmptyStrings(); + Set flags = lines.filter(Objects::nonNull) + .map(String::trim) + .filter(line -> line.startsWith("flags")) + .map(String::toLowerCase) + .flatMap(splitter::splitToStream) + .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder())); + return flags.containsAll(jdk8292158ImpactedCpuFlags); + } + + @VisibleForTesting + static boolean isAesCtrBroken() { + try { + for (int i = 8; i <= 32; i++) { + testEncryptDecrypt(i); + } + return false; + } catch (NoSuchProviderException e) { + log.warn("AES-CTR test failed due to no such provider", e); + return false; + } catch (GeneralSecurityException | Error | RuntimeException e) { + log.error("AES-CTR AES-CTR encryption/decryption round-trip failed", e); + return true; + } + } + + static void testEncryptDecrypt(int length) throws GeneralSecurityException { + Preconditions.checkArgument(length > 4, "length must be at least 4"); + + long seed = ThreadLocalRandom.current().nextLong(); + if (log.isDebugEnabled()) { + log.debug( + "Testing AES-CTR encryption/decryption for JDK-829158", + SafeArg.of("seed", seed), + SafeArg.of("length", length)); + } + + Random random = new Random(seed); + + byte[] key = new byte[32]; + random.nextBytes(key); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); + + byte[] iv = new byte[16]; + random.nextBytes(iv); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + + Cipher encrypt = Cipher.getInstance("AES/CTR/NoPadding"); + encrypt.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + + Cipher decrypt = Cipher.getInstance("AES/CTR/NoPadding"); + decrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); + + byte[] cleartext = new byte[length]; + byte[] encrypted = new byte[length]; + byte[] decrypted = new byte[length]; + + for (int i = 0; i < 10_000; i++) { + random.nextBytes(cleartext); + encrypt.doFinal(cleartext, 0, length, encrypted); + + // use decrypt cipher at least 3 times + decrypt.update(encrypted, 0, 1, decrypted, 0); + decrypt.update(encrypted, 1, 1, decrypted, 1); + decrypt.doFinal(encrypted, 2, length - 2, decrypted, 2); + + if (!Arrays.equals(cleartext, decrypted)) { + throw new SafeIllegalStateException( + "AES-CTR encryption/decryption round trip failed", + cannotEncryptAesCtrSafely(), + SafeArg.of("seed", seed), + SafeArg.of("length", length), + SafeArg.of("iteration", i), + UnsafeArg.of("cleartext", BaseEncoding.base16().encode(cleartext)), + UnsafeArg.of("decrypted", BaseEncoding.base16().encode(decrypted)), + UnsafeArg.of("encrypted", BaseEncoding.base16().encode(encrypted)), + UnsafeArg.of("key", BaseEncoding.base16().encode(key)), + UnsafeArg.of("iv", BaseEncoding.base16().encode(iv))); + } + } + } +} diff --git a/crypto-core/src/main/java/com/palantir/crypto2/io/CryptoStreamFactory.java b/crypto-core/src/main/java/com/palantir/crypto2/io/CryptoStreamFactory.java index 27a14db8a..6f5e839d2 100644 --- a/crypto-core/src/main/java/com/palantir/crypto2/io/CryptoStreamFactory.java +++ b/crypto-core/src/main/java/com/palantir/crypto2/io/CryptoStreamFactory.java @@ -19,6 +19,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Suppliers; import com.palantir.crypto2.cipher.ApacheCiphers; +import com.palantir.crypto2.cipher.Jdk8292158; import com.palantir.crypto2.cipher.SeekableCipher; import com.palantir.crypto2.cipher.SeekableCipherFactory; import com.palantir.crypto2.keys.KeyMaterial; @@ -121,6 +122,9 @@ private static OutputStream createApacheEncryptedStream(OutputStream output, Key private static OutputStream createDefaultEncryptedStream( OutputStream output, KeyMaterial keyMaterial, String algorithm) { SeekableCipher cipher = SeekableCipherFactory.getCipher(algorithm, keyMaterial); + if (Jdk8292158.isAffectedByJdkAesCtrCorruption(algorithm)) { + throw Jdk8292158.cannotEncryptAesCtrSafely(); + } return new ChunkingOutputStream(new CipherOutputStream(output, cipher.initCipher(Cipher.ENCRYPT_MODE))); } diff --git a/crypto-core/src/test/java/com/palantir/crypto2/cipher/Jdk8292158Test.java b/crypto-core/src/test/java/com/palantir/crypto2/cipher/Jdk8292158Test.java new file mode 100644 index 000000000..f2f3c965f --- /dev/null +++ b/crypto-core/src/test/java/com/palantir/crypto2/cipher/Jdk8292158Test.java @@ -0,0 +1,217 @@ +/* + * (c) Copyright 2022 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.crypto2.cipher; + +import static com.palantir.logsafe.testing.Assertions.assertThatLoggableExceptionThrownBy; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assumptions.assumeThatThrownBy; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.palantir.logsafe.Arg; +import com.palantir.logsafe.SafeArg; +import com.palantir.logsafe.exceptions.SafeIllegalStateException; +import java.lang.ProcessHandle.Info; +import java.lang.Runtime.Version; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.function.BooleanSupplier; +import java.util.stream.Stream; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; + +class Jdk8292158Test { + private static final Version AFFECTED_JDK_11 = Version.parse("11.0.17"); + private static final Version FIXED_JDK_11 = Version.parse("11.0.18"); + private static final Version AFFECTED_JDK_17 = Version.parse("17.0.5"); + private static final Version FIXED_JDK_17 = Version.parse("17.0.6"); + private static final ImmutableList architectures = ImmutableList.of("aarch64", "amd64", "x64", "x86"); + + private final Info info = mock(Info.class); + + @Test + void aesCbcIsNotAffected() { + assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption("AES/CBC/PKCS5Padding")) + .isFalse(); + } + + @Test + void throwsWhenAffected() { + assumeTrue(Jdk8292158.isAesCtrBroken()); + assumeThatThrownBy(() -> Jdk8292158.isAffectedByJdkAesCtrCorruption(AesCtrCipher.ALGORITHM)) + .isInstanceOf(SafeIllegalStateException.class) + .hasMessageContaining("JVM and CPU architecture is affected by JDK-8292158"); + } + + @Test + void doesNotThrowWhenNotAffected() { + assumeFalse(Jdk8292158.isAesCtrBroken()); + assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption(AesCtrCipher.ALGORITHM)) + .isFalse(); + } + + @Test + void aesCtrMayBeAffected() { + assumeThatThrownBy(() -> assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption(AesCtrCipher.ALGORITHM)) + .isFalse()) + .isInstanceOf(SafeIllegalStateException.class) + .hasMessageContaining("JVM and CPU architecture is affected by JDK-8292158"); + } + + @Test + void aarch64() { + when(info.arguments()).thenReturn(Optional.empty()); + assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption(AFFECTED_JDK_11, "aarch64", info)) + .isFalse(); + assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption(AFFECTED_JDK_17, "aarch64", info)) + .isFalse(); + } + + @Test + void unaffectedVersion() { + when(info.arguments()).thenReturn(Optional.empty()); + architectures.forEach(arch -> { + assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption(FIXED_JDK_11, arch, info)) + .isFalse(); + assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption(FIXED_JDK_17, arch, info)) + .isFalse(); + }); + } + + @Test + void unaffectedAvx2() { + when(info.arguments()).thenReturn(Optional.of(new String[] {"-XX:UseAVX=2"})); + assertThat(Jdk8292158.isAffectedByJdkAesCtrCorruption(AFFECTED_JDK_11, "x64", info)) + .isFalse(); + } + + @Test + void affected() { + when(info.arguments()).thenReturn(Optional.empty()); + BooleanSupplier hasVectorizedAesAvx512 = () -> true; + + assertThatLoggableExceptionThrownBy(() -> Jdk8292158.isAffectedByJdkAesCtrCorruption( + AFFECTED_JDK_11, "x64", info, hasVectorizedAesAvx512)) + .isInstanceOf(SafeIllegalStateException.class) + .hasMessageContaining("JVM and CPU architecture is affected by JDK-8292158. Add JVM arguments " + + "`-XX:+UnlockDiagnosticVMOptions -XX:-UseAESCTRIntrinsics`") + .args() + .satisfies(args -> { + assertThat(args).hasSize(3); + assertThat(args).allSatisfy(arg -> assertThat(arg) + .isInstanceOf(SafeArg.class) + .extracting(Arg::isSafeForLogging) + .asInstanceOf(InstanceOfAssertFactories.BOOLEAN) + .isTrue()); + }) + .extracting(Arg::getName) + .containsExactlyInAnyOrder("architecture", "version", "jvmArgs"); + + assertThatLoggableExceptionThrownBy(() -> Jdk8292158.isAffectedByJdkAesCtrCorruption( + AFFECTED_JDK_17, "x64", info, hasVectorizedAesAvx512)) + .isInstanceOf(SafeIllegalStateException.class) + .hasMessageContaining("JVM and CPU architecture is affected by JDK-8292158. Add JVM arguments " + + "`-XX:+UnlockDiagnosticVMOptions -XX:-UseAESCTRIntrinsics`") + .args() + .satisfies(args -> { + assertThat(args).hasSize(3); + assertThat(args).allSatisfy(arg -> assertThat(arg) + .isInstanceOf(SafeArg.class) + .extracting(Arg::isSafeForLogging) + .asInstanceOf(InstanceOfAssertFactories.BOOLEAN) + .isTrue()); + }) + .extracting(Arg::getName) + .containsExactlyInAnyOrder("architecture", "version", "jvmArgs"); + } + + @Test + void cascadeLakeIsUnaffected() { + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags\t\t: " + + "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat " + + "pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm " + + "constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf " + + "tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic " + + "movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor " + + "lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase tsc_adjust bmi1 avx2 " + + "smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb " + + "avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves ida arat pku ospke "))) + .isFalse(); + assertThat(Paths.get("src/test/resources/proc-info-cascade-lake.txt")).satisfies(path -> { + assertThat(path).isReadable().isNotEmptyFile(); + assertThat(Jdk8292158.hasVectorizedAesCpu(path)).isFalse(); + }); + } + + @Test + void iceLakeIsAffected() { + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags\t\t: " + + "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat " + + "pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm " + + "constant_tsc rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu " + + "pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt " + + "tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm " + + "3dnowprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced " + + "fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid " + + "avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni " + + "avx512bw avx512vl xsaveopt xsavec xgetbv1 ida arat avx512vbmi pku ospke " + + "avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq " + + "md_clear spec_ctrl intel_stibp flush_l1d arch_capabilities"))) + .isTrue(); + + assertThat(Paths.get("src/test/resources/proc-info-ice-lake.txt")).satisfies(path -> { + assertThat(path).isReadable().isNotEmptyFile(); + assertThat(Jdk8292158.hasVectorizedAesCpu(path)).isTrue(); + }); + } + + @Test + void affectedWhenAllCpuFlags() { + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : avx512bw avx512vl vaes vpclmulqdq"))) + .as("Affected when all four CPU flags exist: %s", Jdk8292158.jdk8292158ImpactedCpuFlags) + .isTrue(); + + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : aes avx512"))) + .as("not affected with just aes and avx512") + .isFalse(); + + // must have all 4 flags to be affected + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : avx512bw"))) + .isFalse(); + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : avx512vl"))) + .isFalse(); + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : vaes"))).isFalse(); + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : vpclmulqdq"))) + .isFalse(); + } + + @Test + void cpuFlagsNoAesAndAvx512() { + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : aes avx avx2 sse2"))) + .isFalse(); + assertThat(Jdk8292158.hasVectorizedAesCpu(Stream.of("flags : fpu avx avx2 avx512"))) + .isFalse(); + + assertThat(Paths.get("src/test/resources/proc-info-no-avx512.txt")).satisfies(path -> { + assertThat(path).isReadable().isNotEmptyFile(); + assertThat(Jdk8292158.hasVectorizedAesCpu(path)).isFalse(); + }); + } +} diff --git a/crypto-core/src/test/resources/proc-info-cascade-lake.txt b/crypto-core/src/test/resources/proc-info-cascade-lake.txt new file mode 100644 index 000000000..f091d3de3 --- /dev/null +++ b/crypto-core/src/test/resources/proc-info-cascade-lake.txt @@ -0,0 +1,26 @@ +processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 85 +model name : Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz +stepping : 7 +microcode : 0x500320a +cpu MHz : 3098.808 +cache size : 36608 KB +physical id : 0 +siblings : 16 +core id : 7 +cpu cores : 8 +apicid : 15 +initial apicid : 15 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves ida arat pku ospke +bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit mmio_stale_data retbleed +bogomips : 4999.99 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: diff --git a/crypto-core/src/test/resources/proc-info-ice-lake.txt b/crypto-core/src/test/resources/proc-info-ice-lake.txt new file mode 100644 index 000000000..bcf41b2cf --- /dev/null +++ b/crypto-core/src/test/resources/proc-info-ice-lake.txt @@ -0,0 +1,25 @@ +processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 106 +model name : Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz +stepping : 6 +microcode : 0xd000331 +cpu MHz : 2899.960 +cache size : 55296 KB +physical id : 0 +siblings : 16 +core id : 7 +cpu cores : 8 +apicid : 15 +initial apicid : 15 +fpu : yes +fpu_exception : yes +cpuid level : 27 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 ida arat avx512vbmi pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq md_clear spec_ctrl intel_stibp flush_l1d arch_capabilities +bogomips : 5799.92 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: diff --git a/crypto-core/src/test/resources/proc-info-no-avx512.txt b/crypto-core/src/test/resources/proc-info-no-avx512.txt new file mode 100644 index 000000000..94dcba85c --- /dev/null +++ b/crypto-core/src/test/resources/proc-info-no-avx512.txt @@ -0,0 +1,26 @@ +processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 85 +model name : Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz +stepping : 7 +microcode : 0x500320a +cpu MHz : 3173.206 +cache size : 36608 KB +physical id : 0 +siblings : 16 +core id : 7 +cpu cores : 8 +apicid : 15 +initial apicid : 15 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx rdseed adx smap clflushopt clwb xsaveopt xsavec xgetbv1 xsaves ida arat pku ospke +bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit mmio_stale_data retbleed +bogomips : 4999.99 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: