org.picketlink.json.jose.crypto.AESGCM.java Source code

Java tutorial

Introduction

Here is the source code for org.picketlink.json.jose.crypto.AESGCM.java

Source

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2012, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.picketlink.json.jose.crypto;

import java.security.SecureRandom;

import javax.crypto.SecretKey;

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;

/**
 * AES/GSM/NoPadding encryption and decryption methods.
 *
 * <p>
 * See draft-ietf-jose-json-web-algorithms-26, section 5.1 and appendix 3.
 *
 * @author Giriraj Sharma
 */
public class AESGCM {

    /**
     * The standard Initialization Vector (IV) length (96 bits).
     */
    public static final int IV_BIT_LENGTH = 96;

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

    /**
     * Generates a random 96 bit (12 byte) Initialization Vector(IV) for use in AES-GCM encryption.
     *
     * <p>
     * See draft-ietf-jose-json-web-algorithms-26, section 5.3.
     *
     * @param randomGen The secure random generator to use. Must be correctly initialized and not {@code null}.
     *
     * @return The random 96 bit IV, as 12 byte array.
     */
    public static byte[] generateIV(final SecureRandom randomGen) {

        byte[] bytes = new byte[IV_BIT_LENGTH / 8];
        randomGen.nextBytes(bytes);
        return bytes;
    }

    /**
     * Creates a new AES/GCM/NoPadding cipher.
     *
     * @param secretKey The AES key. Must not be {@code null}.
     * @param forEncryption If {@code true} creates an encryption cipher, else creates a decryption cipher.
     * @param iv The initialisation vector (IV). Must not be {@code null}.
     * @param authData The authenticated data. Must not be {@code null}.
     *
     * @return The AES/GCM/NoPadding cipher.
     */
    private static GCMBlockCipher createAESGCMCipher(final SecretKey secretKey, final boolean forEncryption,
            final byte[] iv, final byte[] authData) {

        // Initialize AES cipher
        BlockCipher cipher = AES.createCipher(secretKey, forEncryption);

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

        AEADParameters aeadParams = new AEADParameters(new KeyParameter(secretKey.getEncoded()),
                AUTH_TAG_BIT_LENGTH, iv, authData);
        gcm.init(forEncryption, aeadParams);

        return gcm;
    }

    /**
     * Encrypts the specified plain text using AES/GCM/NoPadding.
     *
     * @param secretKey The AES key. Must not be {@code null}.
     * @param plainText The plain text. Must not be {@code null}.
     * @param iv The initialization vector (IV). Must not be {@code null}.
     * @param authData The authenticated data. Must not be {@code null}.
     *
     * @return The authenticated cipher text.
     *
     * @throws RuntimeException If encryption failed.
     */
    public static AuthenticatedCipherText encrypt(final SecretKey secretKey, final byte[] iv,
            final byte[] plainText, final byte[] authData) {

        // Initialise AES/GCM cipher for encryption
        GCMBlockCipher cipher = createAESGCMCipher(secretKey, true, iv, authData);

        // Prepare output buffer
        int outputLength = cipher.getOutputSize(plainText.length);
        byte[] output = new byte[outputLength];

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

        // Produce authentication tag
        try {
            outputOffset += cipher.doFinal(output, outputOffset);
        } catch (InvalidCipherTextException e) {
            throw new RuntimeException("Couldn't generate GCM authentication tag: " + 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 cipher text using AES/GCM/NoPadding.
     *
     * @param secretKey The AES key. Must not be {@code null}.
     * @param iv The initialisation vector (IV). Must not be {@code null}.
     * @param cipherText The cipher text. Must not be {@code null}.
     * @param authData The authenticated data. Must not be {@code null}.
     * @param authTag The authentication tag. Must not be {@code null}.
     *
     * @return The decrypted plain text.
     *
     * @throws RuntimeException If decryption failed.
     */
    public static byte[] decrypt(final SecretKey secretKey, final byte[] iv, final byte[] cipherText,
            final byte[] authData, final byte[] authTag) {

        // Initialise AES/GCM cipher for decryption
        GCMBlockCipher cipher = createAESGCMCipher(secretKey, false, iv, authData);

        // Join cipher text 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 outputLength = cipher.getOutputSize(input.length);

        byte[] output = new byte[outputLength];

        // Decrypt
        int outputOffset = cipher.processBytes(input, 0, input.length, output, 0);

        // Validate authentication tag
        try {
            outputOffset += cipher.doFinal(output, outputOffset);
        } catch (InvalidCipherTextException e) {
            throw new RuntimeException("Couldn't validate GCM authentication tag: " + e.getMessage(), e);
        }
        return output;
    }

    /**
     * Prevents public instantiation.
     */
    private AESGCM() {
    }
}