From 909e2a927e5092dcbbd11857168e962dfa44b338 Mon Sep 17 00:00:00 2001 From: mkeskells Date: Wed, 17 Dec 2025 00:45:58 +0000 Subject: [PATCH] perf: avoid expensive call to Mac.getInstance --- .../encryptionsdk/CryptoAlgorithm.java | 8 +++-- .../encryptionsdk/internal/CommittedKey.java | 4 +-- .../internal/HmacKeyDerivationFunction.java | 15 +++------ .../encryptionsdk/internal/MacAlgorithm.java | 32 +++++++++++++++++++ .../internal/CommittedKeyTest.java | 2 +- .../HmacKeyDerivationFunctionTest.java | 18 +++++------ 6 files changed, 54 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/amazonaws/encryptionsdk/internal/MacAlgorithm.java diff --git a/src/main/java/com/amazonaws/encryptionsdk/CryptoAlgorithm.java b/src/main/java/com/amazonaws/encryptionsdk/CryptoAlgorithm.java index 49c01293d..ee654a9d4 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/CryptoAlgorithm.java +++ b/src/main/java/com/amazonaws/encryptionsdk/CryptoAlgorithm.java @@ -7,6 +7,7 @@ import com.amazonaws.encryptionsdk.internal.CommittedKey; import com.amazonaws.encryptionsdk.internal.Constants; import com.amazonaws.encryptionsdk.internal.HmacKeyDerivationFunction; +import com.amazonaws.encryptionsdk.internal.MacAlgorithm; import com.amazonaws.encryptionsdk.model.CiphertextHeaders; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -342,7 +343,7 @@ private SecretKey getCommittedEncryptionKey( private SecretKey getNonCommittedEncryptionKey( final SecretKey dataKey, final CiphertextHeaders headers) throws InvalidKeyException { - final String macAlgorithm; + final MacAlgorithm macAlgorithm; switch (this) { case ALG_AES_128_GCM_IV12_TAG16_NO_KDF: @@ -353,11 +354,11 @@ private SecretKey getNonCommittedEncryptionKey( case ALG_AES_192_GCM_IV12_TAG16_HKDF_SHA256: case ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA256: case ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256_ECDSA_P256: - macAlgorithm = "HmacSHA256"; + macAlgorithm = MacAlgorithm.HmacSHA256; break; case ALG_AES_192_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384: case ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384: - macAlgorithm = "HmacSHA384"; + macAlgorithm = MacAlgorithm.HmacSHA384; break; default: throw new UnsupportedOperationException("Support for " + this + " not yet built."); @@ -393,3 +394,4 @@ private SecretKey getNonCommittedEncryptionKey( return new SecretKeySpec(hkdf.deriveKey(info.array(), getKeyLength()), getKeyAlgo()); } } + diff --git a/src/main/java/com/amazonaws/encryptionsdk/internal/CommittedKey.java b/src/main/java/com/amazonaws/encryptionsdk/internal/CommittedKey.java index fa3cd84d9..9fd1d3af3 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/internal/CommittedKey.java +++ b/src/main/java/com/amazonaws/encryptionsdk/internal/CommittedKey.java @@ -80,10 +80,10 @@ public static CommittedKey generate(CryptoAlgorithm alg, SecretKey dataKey, byte + rawDataKey.length); } - final String macAlgorithm; + final MacAlgorithm macAlgorithm; switch (alg.getKeyCommitmentAlgo_()) { case HKDF_SHA_512: - macAlgorithm = HMAC_SHA_512; + macAlgorithm = MacAlgorithm.HkdfSHA512; break; default: throw new UnsupportedOperationException( diff --git a/src/main/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunction.java b/src/main/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunction.java index 8c4f4f388..4fd9b37a7 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunction.java +++ b/src/main/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunction.java @@ -48,11 +48,9 @@ public final class HmacKeyDerivationFunction { * @throws NoSuchAlgorithmException if no Provider supports a MacSpi implementation for the * specified algorithm. */ - public static HmacKeyDerivationFunction getInstance(final String algorithm) + public static HmacKeyDerivationFunction getInstance(final MacAlgorithm algorithm) throws NoSuchAlgorithmException { - // Constructed specifically to sanity-test arguments. - Mac mac = Mac.getInstance(algorithm); - return new HmacKeyDerivationFunction(algorithm, mac.getProvider()); + return new HmacKeyDerivationFunction(algorithm); } /** @@ -94,12 +92,9 @@ public void init(final byte[] ikm, final byte[] salt) { } } - private HmacKeyDerivationFunction(final String algorithm, final Provider provider) { - isTrue( - algorithm.startsWith("Hmac"), - "Invalid algorithm " + algorithm + ". Hkdf may only be used with Hmac algorithms."); - this.algorithm = algorithm; - this.provider = provider; + private HmacKeyDerivationFunction(final MacAlgorithm algorithm) throws NoSuchAlgorithmException { + this.algorithm = algorithm.getAlgorithm(); + this.provider = algorithm.getProvider(); } /** diff --git a/src/main/java/com/amazonaws/encryptionsdk/internal/MacAlgorithm.java b/src/main/java/com/amazonaws/encryptionsdk/internal/MacAlgorithm.java new file mode 100644 index 000000000..ff89e03da --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/internal/MacAlgorithm.java @@ -0,0 +1,32 @@ +package com.amazonaws.encryptionsdk.internal; + +import javax.crypto.Mac; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; + +public enum MacAlgorithm { + HmacSHA256("HmacSHA256"), + HmacSHA384("HmacSHA384"), + HmacSHA512("HmacSHA512"), + HkdfSHA512("HkdfSHA512"), + HmacSHA1("HmacSHA1"); + private final String algorithm; + private Provider provider; + + MacAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + Provider getProvider() throws NoSuchAlgorithmException { + Provider provider = this.provider; + if (provider == null) { + provider = Mac.getInstance(algorithm).getProvider(); + this.provider = provider; + } + return provider; + } + + String getAlgorithm() { + return algorithm; + } +} diff --git a/src/test/java/com/amazonaws/encryptionsdk/internal/CommittedKeyTest.java b/src/test/java/com/amazonaws/encryptionsdk/internal/CommittedKeyTest.java index b33f0bec2..bb0cd7784 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/internal/CommittedKeyTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/internal/CommittedKeyTest.java @@ -108,7 +108,7 @@ public void testGenerateCommittedKeySmokeTest() throws Exception { final byte[] n1 = insecureRandomBytes(32); // Hash for HKDF is SHA-512 - final HmacKeyDerivationFunction hkdf = HmacKeyDerivationFunction.getInstance("HmacSHA512"); + final HmacKeyDerivationFunction hkdf = HmacKeyDerivationFunction.getInstance(MacAlgorithm.HmacSHA512); // K_R (Raw keying material, a.k.a. data key) is 256 bits (32 bytes) // Normally this needs to be cryptographically secure, but we can relax this for improved diff --git a/src/test/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunctionTest.java b/src/test/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunctionTest.java index 7cea2c616..e9be209f8 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunctionTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/internal/HmacKeyDerivationFunctionTest.java @@ -21,7 +21,7 @@ public class HmacKeyDerivationFunctionTest { private static final testCase[] testCases = new testCase[] { new testCase( - "HmacSHA256", + MacAlgorithm.HmacSHA256, fromCHex( "\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b" + "\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b"), @@ -30,7 +30,7 @@ public class HmacKeyDerivationFunctionTest { fromHex( "3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56ECC4C5BF34007208D5B887185865")), new testCase( - "HmacSHA256", + MacAlgorithm.HmacSHA256, fromCHex( "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d" + "\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b" @@ -60,7 +60,7 @@ public class HmacKeyDerivationFunctionTest { + "CC30C58179EC3E87C14C01D5C1F3434F" + "1D87")), new testCase( - "HmacSHA256", + MacAlgorithm.HmacSHA256, fromCHex( "\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b" + "\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b"), @@ -71,7 +71,7 @@ public class HmacKeyDerivationFunctionTest { + "B8A11F5C5EE1879EC3454E5F3C738D2D" + "9D201395FAA4B61A96C8")), new testCase( - "HmacSHA1", + MacAlgorithm.HmacSHA1, fromCHex("\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b"), fromCHex("\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c"), fromCHex("\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9"), @@ -80,7 +80,7 @@ public class HmacKeyDerivationFunctionTest { + "A4F14B822F5B091568A9CDD4F155FDA2" + "C22E422478D305F3F896")), new testCase( - "HmacSHA1", + MacAlgorithm.HmacSHA1, fromCHex( "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d" + "\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b" @@ -109,7 +109,7 @@ public class HmacKeyDerivationFunctionTest { + "486EA37CE3D397ED034C7F9DFEB15C5E" + "927336D0441F4C4300E2CFF0D0900B52D3B4")), new testCase( - "HmacSHA1", + MacAlgorithm.HmacSHA1, fromCHex( "\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b" + "\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b"), @@ -117,7 +117,7 @@ public class HmacKeyDerivationFunctionTest { new byte[0], fromHex("0AC1AF7002B3D761D1E55298DA9D0506" + "B9AE52057220A306E07B6B87E8DF21D0")), new testCase( - "HmacSHA1", + MacAlgorithm.HmacSHA1, fromCHex( "\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c" + "\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c"), @@ -200,13 +200,13 @@ private static byte[] fromCHex(String data) { } private static class testCase { - public final String algo; + public final MacAlgorithm algo; public final byte[] ikm; public final byte[] salt; public final byte[] info; public final byte[] expected; - testCase(String algo, byte[] ikm, byte[] salt, byte[] info, byte[] expected) { + testCase(MacAlgorithm algo, byte[] ikm, byte[] salt, byte[] info, byte[] expected) { super(); this.algo = algo; this.ikm = ikm;