All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.groupbyinc.common.security.AesDecryption Maven / Gradle / Ivy

The newest version!
package com.groupbyinc.common.security;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import static com.groupbyinc.common.security.AesEncryption.CLIENT_KEY_HASHING_ITERATIONS;
import static com.groupbyinc.common.security.AesUtil.geEncryptSalt;
import static com.groupbyinc.common.security.AesUtil.getMessageAuthenticationCodeSalt;
import static java.nio.charset.StandardCharsets.UTF_8;

public class AesDecryption {

  private SecretKey encryptionKey;
  private Cipher cipher;
  private SecretKey macKey;
  private Mac hmac;

  public AesDecryption(String clientKey, String customerId)
      throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
    this(clientKey, customerId, new BouncyCastleProvider());
  }

  public AesDecryption(String clientKey, String customerId, Provider provider) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
    Security.addProvider(provider);
    cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(clientKey.toCharArray(), geEncryptSalt(customerId).getBytes(StandardCharsets.UTF_8), CLIENT_KEY_HASHING_ITERATIONS, 128);
    KeySpec macSpec = new PBEKeySpec(clientKey.toCharArray(), getMessageAuthenticationCodeSalt(customerId).getBytes(StandardCharsets.UTF_8), CLIENT_KEY_HASHING_ITERATIONS, 160);
    encryptionKey = new SecretKeySpec(factory.generateSecret(spec)
                                          .getEncoded(), "AES");
    macKey = new SecretKeySpec(factory.generateSecret(macSpec)
                                   .getEncoded(), "HmacSHA256");
    hmac = Mac.getInstance("HmacSHA256");
    hmac.init(macKey);
  }

  public String decrypt(AesContent aesContent) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    if (aesContent == null) {
      throw new IllegalStateException("cannot decrypt null AesContent");
    } else if (StringUtils.isBlank(aesContent.getCipherText()) || StringUtils.isBlank(aesContent.getInitialValue()) || StringUtils.isBlank(aesContent.getMessageAuthenticationCode())) {
      throw new IllegalStateException("cipher text, IV and messageAuthenticationCode must be provided");
    }

    byte[] ivBytes = Base64.decodeBase64(aesContent.getInitialValue()
                                       .getBytes(UTF_8));
    byte[] cipherTextBytes = Base64.decodeBase64(aesContent.getCipherText()
                                               .getBytes(UTF_8));
    byte[] macBytes = Base64.decodeBase64(aesContent.getMessageAuthenticationCode()
                                        .getBytes(UTF_8));

    if (!validateMac(ivBytes, cipherTextBytes, macBytes)) {
      throw new IllegalStateException("MAC does not match");
    }

    IvParameterSpec iv = new IvParameterSpec(ivBytes);
    cipher.init(Cipher.DECRYPT_MODE, encryptionKey, iv);
    byte[] original = cipher.doFinal(cipherTextBytes);

    return new String(original, UTF_8);
  }

  public boolean validateMac(AesContent aesContent) {
    if (aesContent == null) {
      throw new IllegalStateException("cannot decrypt null AesContent");
    } else if (StringUtils.isBlank(aesContent.getCipherText()) || StringUtils.isBlank(aesContent.getInitialValue()) || StringUtils.isBlank(aesContent.getMessageAuthenticationCode())) {
      throw new IllegalStateException("cipher text, IV and messageAuthenticationCode must be provided");
    }
    byte[] ivBytes = Base64.decodeBase64(aesContent.getInitialValue()
                                       .getBytes(UTF_8));
    byte[] cipherTextBytes = Base64.decodeBase64(aesContent.getCipherText()
                                               .getBytes(UTF_8));
    byte[] macBytes = Base64.decodeBase64(aesContent.getMessageAuthenticationCode()
                                        .getBytes(UTF_8));
    return validateMac(ivBytes, cipherTextBytes, macBytes);
  }

  private boolean validateMac(byte[] ivBytes, byte[] cipherTextBytes, byte[] macBytes) {
    byte[] ciperTextAndIv = new byte[cipherTextBytes.length + ivBytes.length];
    System.arraycopy(cipherTextBytes, 0, ciperTextAndIv, 0, cipherTextBytes.length);
    System.arraycopy(ivBytes, 0, ciperTextAndIv, cipherTextBytes.length, ivBytes.length);
    byte[] mac = hmac.doFinal(ciperTextAndIv);
    return MessageDigest.isEqual(mac, macBytes);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy