OpenSslCipher.java

  1.  /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *     http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing, software
  13.  * distributed under the License is distributed on an "AS IS" BASIS,
  14.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  * See the License for the specific language governing permissions and
  16.  * limitations under the License.
  17.  */
  18. package org.apache.commons.crypto.cipher;

  19. import java.nio.ByteBuffer;
  20. import java.security.GeneralSecurityException;
  21. import java.security.InvalidAlgorithmParameterException;
  22. import java.security.InvalidKeyException;
  23. import java.security.Key;
  24. import java.security.spec.AlgorithmParameterSpec;
  25. import java.util.Objects;
  26. import java.util.Properties;

  27. import javax.crypto.BadPaddingException;
  28. import javax.crypto.Cipher;
  29. import javax.crypto.IllegalBlockSizeException;
  30. import javax.crypto.ShortBufferException;

  31. /**
  32.  * Implements the CryptoCipher using JNI into OpenSSL.
  33.  * <p>
  34.  * this class is not public/protected so does not appear in the main Javadoc Please ensure that property use is documented in the enum
  35.  * CryptoRandomFactory.RandomProvider
  36.  * </p>
  37.  */
  38. final class OpenSslCipher implements CryptoCipher {

  39.     private final OpenSsl openSslEngine;
  40.     private boolean initialized;

  41.     private final String transformation;

  42.     /**
  43.      * Constructs a {@link CryptoCipher} using JNI into OpenSSL
  44.      *
  45.      * @param props  properties for OpenSSL openSslEngine (unused)
  46.      * @param transformation  transformation for OpenSSL openSslEngine (algorithm/mode/padding)
  47.      * @throws GeneralSecurityException if OpenSSL openSslEngine initialize failed
  48.      */
  49.     public OpenSslCipher(final Properties props, final String transformation) // NOPMD
  50.             throws GeneralSecurityException {
  51.         this.transformation = transformation;

  52.         final Throwable loadingFailureReason = OpenSsl.getLoadingFailureReason();
  53.         if (loadingFailureReason != null) {
  54.             throw new IllegalStateException(loadingFailureReason);
  55.         }

  56.         openSslEngine = OpenSsl.getInstance(transformation);
  57.     }

  58.     /**
  59.      * Closes the OpenSSL openSslEngine. Clean the OpenSsl native context.
  60.      */
  61.     @Override
  62.     public void close() {
  63.         openSslEngine.clean();
  64.     }

  65.     /**
  66.      * Encrypts or decrypts data in a single-part operation, or finishes a
  67.      * multiple-part operation.
  68.      *
  69.      * @param input the input byte array
  70.      * @param inputOffset the offset in input where the input starts
  71.      * @param inputLen the input length
  72.      * @param output the byte array for the result
  73.      * @param outputOffset the offset in output where the result is stored
  74.      * @return the number of bytes stored in output
  75.      * @throws ShortBufferException if the given output byte array is too small
  76.      *         to hold the result
  77.      * @throws BadPaddingException if this openSslEngine is in decryption mode, and
  78.      *         (un)padding has been requested, but the decrypted data is not
  79.      *         bounded by the appropriate padding bytes
  80.      * @throws IllegalBlockSizeException if this openSslEngine is a block openSslEngine, no
  81.      *         padding has been requested (only in encryption mode), and the
  82.      *         total input length of the data processed by this openSslEngine is not a
  83.      *         multiple of block size; or if this encryption algorithm is unable
  84.      *         to process the input data provided.
  85.      */
  86.     @Override
  87.     public int doFinal(final byte[] input, final int inputOffset, final int inputLen,
  88.             final byte[] output, final int outputOffset) throws ShortBufferException,
  89.             IllegalBlockSizeException, BadPaddingException {
  90.         return openSslEngine.doFinal(input, inputOffset, inputLen, output,outputOffset);
  91.     }

  92.     /**
  93.      * Encrypts or decrypts data in a single-part operation, or finishes a
  94.      * multiple-part operation. The data is encrypted or decrypted, depending on
  95.      * how this openSslEngine was initialized.
  96.      *
  97.      * @param inBuffer the input ByteBuffer
  98.      * @param outBuffer the output ByteBuffer
  99.      * @return int number of bytes stored in {@code output}
  100.      * @throws BadPaddingException if this openSslEngine is in decryption mode, and
  101.      *         (un)padding has been requested, but the decrypted data is not
  102.      *         bounded by the appropriate padding bytes
  103.      * @throws IllegalBlockSizeException if this openSslEngine is a block openSslEngine, no
  104.      *         padding has been requested (only in encryption mode), and the
  105.      *         total input length of the data processed by this openSslEngine is not a
  106.      *         multiple of block size; or if this encryption algorithm is unable
  107.      *         to process the input data provided.
  108.      * @throws ShortBufferException if the given output buffer is too small to
  109.      *         hold the result
  110.      */
  111.     @Override
  112.     public int doFinal(final ByteBuffer inBuffer, final ByteBuffer outBuffer)
  113.             throws ShortBufferException, IllegalBlockSizeException,
  114.             BadPaddingException {
  115.         return openSslEngine.doFinal(inBuffer, outBuffer);
  116.     }

  117.     /**
  118.      * Returns the algorithm name of this {@code CryptoCipher} object.
  119.      *
  120.      * <p>
  121.      * This is the same name that was specified in one of the
  122.      * {@code CryptoCipherFactory#getInstance} calls that created this
  123.      * {@code CryptoCipher} object..
  124.      * </p>
  125.      *
  126.      * @return the algorithm name of this {@code CryptoCipher} object.
  127.      */
  128.     @Override
  129.     public String getAlgorithm() {
  130.         return transformation;
  131.     }

  132.     /**
  133.      * Returns the block size (in bytes).
  134.      *
  135.      * @return the block size (in bytes), or 0 if the underlying algorithm is
  136.      * not a block openSslEngine
  137.      */
  138.     @Override
  139.     public int getBlockSize() {
  140.         return CryptoCipherFactory.AES_BLOCK_SIZE;
  141.     }

  142.     /**
  143.      * Initializes the openSslEngine with mode, key and iv.
  144.      *
  145.      * @param mode {@link Cipher#ENCRYPT_MODE} or {@link Cipher#DECRYPT_MODE}
  146.      * @param key crypto key for the openSslEngine
  147.      * @param params the algorithm parameters
  148.      * @throws InvalidKeyException If key length is invalid
  149.      * @throws InvalidAlgorithmParameterException if IV length is wrong
  150.      */
  151.     @Override
  152.     public void init(final int mode, final Key key, final AlgorithmParameterSpec params)
  153.             throws InvalidKeyException, InvalidAlgorithmParameterException {
  154.         Objects.requireNonNull(key, "key");
  155.         Objects.requireNonNull(params, "params");

  156.         final int cipherMode = mode == Cipher.ENCRYPT_MODE ? OpenSsl.ENCRYPT_MODE: OpenSsl.DECRYPT_MODE;
  157.         openSslEngine.init(cipherMode, key.getEncoded(), params);
  158.         initialized = true;
  159.     }

  160.     /**
  161.      * Continues a multiple-part encryption/decryption operation. The data is
  162.      * encrypted or decrypted, depending on how this openSslEngine was initialized.
  163.      *
  164.      * @param input the input byte array
  165.      * @param inputOffset the offset in input where the input starts
  166.      * @param inputLen the input length
  167.      * @param output the byte array for the result
  168.      * @param outputOffset the offset in output where the result is stored
  169.      * @return the number of bytes stored in output
  170.      * @throws ShortBufferException if there is insufficient space in the output
  171.      *         byte array
  172.      */
  173.     @Override
  174.     public int update(final byte[] input, final int inputOffset, final int inputLen,
  175.             final byte[] output, final int outputOffset) throws ShortBufferException {
  176.         return openSslEngine
  177.                 .update(input, inputOffset, inputLen, output, outputOffset);
  178.     }


  179.     /**
  180.      * Continues a multiple-part encryption/decryption operation. The data is
  181.      * encrypted or decrypted, depending on how this openSslEngine was initialized.
  182.      *
  183.      * @param inBuffer the input ByteBuffer
  184.      * @param outBuffer the output ByteBuffer
  185.      * @return int number of bytes stored in {@code output}
  186.      * @throws ShortBufferException if there is insufficient space in the output
  187.      *         buffer
  188.      */
  189.     @Override
  190.     public int update(final ByteBuffer inBuffer, final ByteBuffer outBuffer)
  191.             throws ShortBufferException {
  192.         return openSslEngine.update(inBuffer, outBuffer);
  193.     }

  194.     /**
  195.      * Continues a multi-part update of the Additional Authentication
  196.      * Data (AAD).
  197.      * <p>
  198.      * Calls to this method provide AAD to the opensslEngine when operating in
  199.      * modes such as AEAD (GCM).  If this opensslEngine is operating in
  200.      * either GCM mode, all AAD must be supplied before beginning
  201.      * operations on the ciphertext (via the {@code update} and
  202.      * {@code doFinal} methods).
  203.      * </p>
  204.      *
  205.      * @param aad the buffer containing the Additional Authentication Data
  206.      *
  207.      * @throws IllegalArgumentException if the {@code aad}
  208.      * byte array is null
  209.      * @throws IllegalStateException if this opensslEngine is in a wrong state
  210.      * (e.g., has not been initialized), does not accept AAD, or if
  211.      * operating in either GCM mode and one of the {@code update}
  212.      * methods has already been called for the active
  213.      * encryption/decryption operation
  214.      * @throws UnsupportedOperationException if the implementation {@code opensslEngine}
  215.      * doesn't support this operation.
  216.      */
  217.     @Override
  218.     public void updateAAD(final byte[] aad) throws IllegalArgumentException,
  219.             IllegalStateException, UnsupportedOperationException {
  220.         if (aad == null) {
  221.             throw new IllegalArgumentException("aad buffer is null");
  222.         }
  223.         if (!initialized) {
  224.             throw new IllegalStateException("Cipher not initialized");
  225.         }
  226.         if (aad.length == 0) {
  227.             return;
  228.         }

  229.         openSslEngine.updateAAD(aad);
  230.     }


  231.     /**
  232.      * Continues a multi-part update of the Additional Authentication
  233.      * Data (AAD).
  234.      * <p>
  235.      * Calls to this method provide AAD to the opensslEngine when operating in
  236.      * modes such as AEAD (GCM).  If this opensslEngine is operating in
  237.      * either GCM mode, all AAD must be supplied before beginning
  238.      * operations on the ciphertext (via the {@code update} and
  239.      * {@code doFinal} methods).
  240.      * </p>
  241.      *
  242.      * @param aad the buffer containing the Additional Authentication Data
  243.      *
  244.      * @throws IllegalArgumentException if the {@code aad}
  245.      * byte array is null
  246.      * @throws IllegalStateException if this opensslEngine is in a wrong state
  247.      * (e.g., has not been initialized), does not accept AAD, or if
  248.      * operating in either GCM mode and one of the {@code update}
  249.      * methods has already been called for the active
  250.      * encryption/decryption operation
  251.      * @throws UnsupportedOperationException if the implementation {@code opensslEngine}
  252.      * doesn't support this operation.
  253.      */
  254.     @Override
  255.     public void updateAAD(final ByteBuffer aad) throws IllegalArgumentException,
  256.             IllegalStateException, UnsupportedOperationException {
  257.         if (aad == null) {
  258.             throw new IllegalArgumentException("aad buffer is null");
  259.         }
  260.         if (!initialized) {
  261.             throw new IllegalStateException("Cipher not initialized");
  262.         }

  263.         final int aadLen = aad.limit() - aad.position();
  264.         if (aadLen == 0) {
  265.             return;
  266.         }
  267.         final byte[] aadBytes = new byte[aadLen];
  268.         aad.get(aadBytes);
  269.         openSslEngine.updateAAD(aadBytes);
  270.     }
  271. }