![JAR search and dependency download from the Maven repository](/logo.png)
com.nimbusds.infinispan.persistence.dynamodb.ItemHMAC Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of infinispan-cachestore-dynamodb Show documentation
Show all versions of infinispan-cachestore-dynamodb Show documentation
Infinispan module for persisting data to an AWS DynamoDB table
package com.nimbusds.infinispan.persistence.dynamodb;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.amazonaws.services.dynamodbv2.document.Item;
import net.jcip.annotations.Immutable;
import org.erdtman.jcs.JsonCanonicalizer;
import com.nimbusds.common.store.StoreException;
/**
* HMAC SHA-256 facility for providing integrity and authenticity to DynamoDB
* items.
*/
@Immutable
final class ItemHMAC {
/**
* The attribute used to store the HMAC SHA-256 in binary format.
*/
public static final String ATTRIBUTE_NAME = "_hmac#s256";
/**
* The HMAC key, {@code null} if disabled.
*/
private final SecretKey hmacKey;
/**
* Creates a new HMAC SHA-256 facility.
*
* @param hmacKeyBase64Encoded The BASE 64 encoded HMAC SHA-256 key
* with at least 256 bits, {@code null} if
* disabled.
*/
public ItemHMAC(final String hmacKeyBase64Encoded)
throws InvalidKeyException {
this (hmacKeyBase64Encoded != null ? Base64.getDecoder().decode(hmacKeyBase64Encoded) : null);
}
/**
* Creates a new HMAC SHA-256 facility.
*
* @param hmacKeyBytes The HMAC SHA-256 key with at least 256 bits,
* {@code null} if disabled.
*/
public ItemHMAC(final byte[] hmacKeyBytes)
throws InvalidKeyException {
this(hmacKeyBytes != null ? new SecretKeySpec(hmacKeyBytes, "HmacSHA256") : null);
}
/**
* Creates a new HMAC SHA-256 facility.
*
* @param hmacKey The HMAC SHA-256 key with JCA algorithm "HmacSHA256"
* and at least 256 bits, {@code null} if disabled.
*/
public ItemHMAC(final SecretKey hmacKey)
throws InvalidKeyException {
this.hmacKey = hmacKey;
if (hmacKey == null) {
return;
}
if (hmacKey.getEncoded().length < (256 / 8)) {
throw new InvalidKeyException("The HMAC SHA-256 key must be at least 256 bits long");
}
}
/**
* Computes the HMAC SHA-256 for the specified DynamoDB item.
*
* @param item The DynamoDB item.
*
* @return The HMAC SHA-256 bytes, {@code null} if HMAC is disabled.
*/
public byte[] compute(final Item item)
throws NoSuchAlgorithmException, InvalidKeyException {
if (hmacKey == null) {
return null;
}
JsonCanonicalizer jc;
try {
jc = new JsonCanonicalizer(item.toJSON());
} catch (IOException e) {
throw new StoreException(e.getMessage(), e);
}
// https://tools.ietf.org/html/rfc8785
byte[] hmacInput = jc.getEncodedString().getBytes(StandardCharsets.UTF_8);
Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
hmacSHA256.init(hmacKey);
return hmacSHA256.doFinal(hmacInput);
}
/**
* Applies an optional HMAC SHA-256 to the specified DynamoDB item
* which is included as the {@link #ATTRIBUTE_NAME _hmac#S256}
* attribute.
*
* @param item The DynamoDB item.
*
* @return The DynamoDB item with included HMAC SHA-256, unmodified if
* HMAC is disabled.
*/
public Item apply(final Item item)
throws InvalidKeyException, NoSuchAlgorithmException {
byte[] hmac = compute(item);
if (hmac == null) {
return item;
}
return item.withBinary(ATTRIBUTE_NAME, hmac);
}
/**
* Verifies the optional HMAC HMAC SHA-256 for the specified DynamoDB
* item.
*
* @param item The DynamoDB item, with optional HMAC SHA-256.
*
* @return The DynamoDB item, with removed HMAC SHA-256 attribute if
* HMAC is enabled, unmodified if HMAC is disabled.
*
* @throws InvalidHMACException If the HMAC SHA-256 check failed.
*/
public Item verify(final Item item)
throws InvalidHMACException, InvalidKeyException, NoSuchAlgorithmException {
if (hmacKey == null) {
return item;
}
if (! item.hasAttribute(ATTRIBUTE_NAME)) {
throw new InvalidHMACException("Missing item HMAC attribute: " + ATTRIBUTE_NAME);
}
byte[] storedHMAC = item.getBinary(ATTRIBUTE_NAME);
Item baseItem = item.removeAttribute(ATTRIBUTE_NAME);
byte[] computedHMAC = compute(baseItem);
if (! MessageDigest.isEqual(storedHMAC, computedHMAC)) {
throw new InvalidHMACException(
"Invalid item HMAC:" +
" Stored: " + Base64.getEncoder().encodeToString(storedHMAC) +
" Computed: " + Base64.getEncoder().encodeToString(computedHMAC) +
" Item: " + item.toJSON()
);
}
return baseItem;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy