Skip to content

Commit

Permalink
Use ThreadLocal for Cipher instances in AesSiv and PrfAesCmac.
Browse files Browse the repository at this point in the history
We already do the same thing for other key type, such as AES-GCM.

See also: #36, and #24.

I run some benchmarks for this, where I encrypt some data using AES-SIV many times.
- For 1kb data, it get 2.5x faster for a single thread, and 5.6x faster for 10 threads in parallel.
- For 32 bytes data, it gets 15x faster for a single thread, and 41x faster for 10 threads in parallel.

PiperOrigin-RevId: 629075782
Change-Id: I6735eafe4670213af15084343a7f269885d1101b
  • Loading branch information
juergw authored and copybara-github committed Apr 29, 2024
1 parent 96e8c0d commit e3074ae
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 3 deletions.
16 changes: 14 additions & 2 deletions src/main/java/com/google/crypto/tink/subtle/AesSiv.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ public static DeterministicAead create(AesSivKey key) throws GeneralSecurityExce
key.getKeyBytes().toByteArray(InsecureSecretKeyAccess.get()), key.getOutputPrefix());
}

private static final ThreadLocal<Cipher> localAesCtrCipher =
new ThreadLocal<Cipher>() {
@Override
protected Cipher initialValue() {
try {
return EngineFactory.CIPHER.getInstance("AES/CTR/NoPadding");
} catch (GeneralSecurityException ex) {
throw new IllegalStateException(ex);
}
}
};

private AesSiv(final byte[] key, Bytes outputPrefix) throws GeneralSecurityException {
if (!FIPS.isCompatible()) {
throw new GeneralSecurityException(
Expand Down Expand Up @@ -132,7 +144,7 @@ public byte[] encryptDeterministically(final byte[] plaintext, final byte[] asso
throw new GeneralSecurityException("plaintext too long");
}

Cipher aesCtr = EngineFactory.CIPHER.getInstance("AES/CTR/NoPadding");
Cipher aesCtr = localAesCtrCipher.get();
byte[] computedIv = s2v(associatedData, plaintext);
byte[] ivForJavaCrypto = computedIv.clone();
ivForJavaCrypto[8] &= (byte) 0x7F; // 63th bit from the right
Expand All @@ -158,7 +170,7 @@ public byte[] decryptDeterministically(final byte[] ciphertext, final byte[] ass
throw new GeneralSecurityException("Decryption failed (OutputPrefix mismatch).");
}

Cipher aesCtr = EngineFactory.CIPHER.getInstance("AES/CTR/NoPadding");
Cipher aesCtr = localAesCtrCipher.get();

byte[] expectedIv =
Arrays.copyOfRange(
Expand Down
14 changes: 13 additions & 1 deletion src/main/java/com/google/crypto/tink/subtle/PrfAesCmac.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,23 @@ public final class PrfAesCmac implements Prf {
@SuppressWarnings("Immutable")
private byte[] subKey2;

private static final ThreadLocal<Cipher> localAesCipher =
new ThreadLocal<Cipher>() {
@Override
protected Cipher initialValue() {
try {
return EngineFactory.CIPHER.getInstance("AES/ECB/NoPadding");
} catch (GeneralSecurityException ex) {
throw new IllegalStateException(ex);
}
}
};

private static Cipher instance() throws GeneralSecurityException {
if (!FIPS.isCompatible()) {
throw new GeneralSecurityException("Can not use AES-CMAC in FIPS-mode.");
}
return EngineFactory.CIPHER.getInstance("AES/ECB/NoPadding");
return localAesCipher.get();
}

public PrfAesCmac(final byte[] key) throws GeneralSecurityException {
Expand Down

0 comments on commit e3074ae

Please sign in to comment.