Package com.nimbusds.jose.crypto

Source Code of com.nimbusds.jose.crypto.AESGCMKW

package com.nimbusds.jose.crypto;


import java.security.Provider;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import net.jcip.annotations.ThreadSafe;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;

import com.nimbusds.jose.JOSEException;


/**
* AES GCM methods for Content Encryption Key (CEK) encryption and
* decryption. Uses the BouncyCastle.org provider. This class is thread-safe.
*
* <p>See draft-ietf-jose-json-web-algorithms-26, section 4.7.
*
* @author Melisa Halsband
* @version $version$ (2014-06-18)
*/
@ThreadSafe
class AESGCMKW {


  /**
   * The standard authentication tag length (128 bits).
   */
  public static final int AUTH_TAG_BIT_LENGTH = 128;


  /**
   * Encrypts the specified Content Encryption Key (CEK).
   *
   * @param cek     The Content Encryption Key (CEK) to encrypt. Must
   *       not be {@code null}.
   * @param iv     The initialisation vector (IV). Must not be
   *       {@code null}.
   * @param kek     The AES Key Encription Key (KEK). Must not be
   *       {@code null}.
   * @param provider The JCA provider, or {@code null} to use the default
   *       one.
   *
   * @return The encrypted Content Encryption Key (CEK).
   *
   * @throws JOSEException If encryption failed.
   */
  public static AuthenticatedCipherText encryptCEK(final SecretKey cek,
               final byte[] iv,
               final SecretKey kek,
               Provider provider)
    throws JOSEException {

    // Initialise AES cipher
    BlockCipher cipher = AES.createCipher(kek, true);

    // Create GCM cipher with AES
    GCMBlockCipher gcm = new GCMBlockCipher(cipher);

    AEADParameters aeadParams = new AEADParameters(new KeyParameter(kek.getEncoded()),
      AUTH_TAG_BIT_LENGTH,
      iv,
      null);
    gcm.init(true, aeadParams);

    // Prepare output buffer
    int outputLength = gcm.getOutputSize(cek.getEncoded().length);
    byte[] output = new byte[outputLength];

    // Produce cipher text
    int outputOffset = gcm.processBytes(cek.getEncoded(), 0, cek.getEncoded().length, output, 0);

    // Produce authentication tag
    try {
      outputOffset += gcm.doFinal(output, outputOffset);

    } catch (InvalidCipherTextException e) {

      throw new JOSEException("Couldn't generate GCM authentication tag for key: " + e.getMessage(), e);
    }

    // Split output into cipher text and authentication tag
    int authTagLength = AUTH_TAG_BIT_LENGTH / 8;

    byte[] cipherText = new byte[outputOffset - authTagLength];
    byte[] authTag = new byte[authTagLength];

    System.arraycopy(output, 0, cipherText, 0, cipherText.length);
    System.arraycopy(output, outputOffset - authTagLength, authTag, 0, authTag.length);

    return new AuthenticatedCipherText(cipherText, authTag);

  }


  /**
   * Decrypts the specified encrypted Content Encryption Key (CEK).
   *
   * @param kek         The AES Key Encription Key. Must not be
   *                     {@code null}.
   * @param iv         The initialisation vector (IV). Must not be
   *           {@code null}.
   * @param authEncrCEK  The encrypted Content Encryption Key (CEK) to
   *           decrypt and authentication tag. Must not be
   *           {@code null}.
   * @param provider     The JCA provider, or {@code null} to use the
   *           default one.
   *
   * @return The decrypted Content Encryption Key (CEK).
   *
   * @throws JOSEException If decryption failed.
   */
  public static SecretKey decryptCEK(final SecretKey kek,
             final byte[] iv,
             final AuthenticatedCipherText authEncrCEK,
             final int keyLength,
             final Provider provider)
    throws JOSEException {

    // Initialise AES cipher
    BlockCipher cipher = AES.createCipher(kek, false);

    // Create GCM cipher with AES
    GCMBlockCipher gcm = new GCMBlockCipher(cipher);

    AEADParameters aeadParams = new AEADParameters(new KeyParameter(kek.getEncoded()),
      AUTH_TAG_BIT_LENGTH,
      iv,
      null);
    gcm.init(false, aeadParams);

    byte[] cipherText = authEncrCEK.getCipherText();
    byte[] authTag = authEncrCEK.getAuthenticationTag();

    // Join encrypted CEK and authentication tag to produce cipher input
    byte[] input = new byte[cipherText.length + authTag.length];

    System.arraycopy(cipherText, 0, input, 0, cipherText.length);
    System.arraycopy(authTag, 0, input, cipherText.length, authTag.length);

    int keyBytesLength = gcm.getOutputSize(input.length);

    byte[] keyBytes = new byte[keyBytesLength];


    // Decrypt
    int keyBytesOffset = gcm.processBytes(input, 0, input.length, keyBytes, 0);


    // Validate authentication tag
    try {
      keyBytesOffset += gcm.doFinal(keyBytes, keyBytesOffset);

    } catch (InvalidCipherTextException e) {

      throw new JOSEException("Couldn't validate GCM authentication tag: " + e.getMessage(), e);
    }

    if (8 * keyBytes.length != keyLength) {

      throw new JOSEException("CEK key length mismatch: " +
        keyBytes.length + " != " + keyLength);
    }

    return new SecretKeySpec(keyBytes, "AES");

  }


  /**
   * Prevents public instantiation.
   */
  private AESGCMKW() { }
}
TOP

Related Classes of com.nimbusds.jose.crypto.AESGCMKW

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.