View Javadoc
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  
20  import java.nio.ByteBuffer;
21  import java.security.GeneralSecurityException;
22  import java.security.InvalidAlgorithmParameterException;
23  import java.security.InvalidKeyException;
24  import java.security.Key;
25  import java.security.spec.AlgorithmParameterSpec;
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  import javax.crypto.spec.IvParameterSpec;
32  
33  import org.apache.commons.crypto.utils.Utils;
34  
35  /**
36   * Implements the CryptoCipher using JNI into OpenSSL.
37   */
38  class OpenSslCipher implements CryptoCipher {
39  
40      private final OpenSsl cipher;
41  
42      private final String transformation;
43  
44      /**
45       * Constructs a {@link CryptoCipher} using JNI into OpenSSL
46       *
47       * @param props  properties for OpenSSL cipher (unused)
48       * @param transformation  transformation for OpenSSL cipher (algorithm/mode/padding)
49       * @throws GeneralSecurityException if OpenSSL cipher initialize failed
50       */
51      // N.B. this class is not public/protected so does not appear in the main Javadoc
52      // Please ensure that property use is documented in the enum CryptoRandomFactory.RandomProvider
53      public OpenSslCipher(Properties props, String transformation) // NOPMD
54              throws GeneralSecurityException {
55          this.transformation = transformation;
56  
57          Throwable loadingFailureReason = OpenSsl.getLoadingFailureReason();
58          if (loadingFailureReason != null) {
59              throw new RuntimeException(loadingFailureReason);
60          }
61  
62          cipher = OpenSsl.getInstance(transformation);
63      }
64  
65      /**
66       * Returns the block size (in bytes).
67       *
68       * @return the block size (in bytes), or 0 if the underlying algorithm is
69       * not a block cipher
70       */
71      @Override
72      public final int getBlockSize() {
73          return CryptoCipherFactory.AES_BLOCK_SIZE;
74      }
75  
76      /**
77       * Returns the algorithm name of this {@code CryptoCipher} object.
78       *
79       * <p>This is the same name that was specified in one of the
80       * {@code CryptoCipherFactory#getInstance} calls that created this
81       * {@code CryptoCipher} object..
82       *
83       * @return the algorithm name of this {@code CryptoCipher} object.
84       */
85      @Override
86      public String getAlgorithm() {
87          return transformation;
88      }
89  
90      /**
91       * Initializes the cipher with mode, key and iv.
92       *
93       * @param mode {@link Cipher#ENCRYPT_MODE} or {@link Cipher#DECRYPT_MODE}
94       * @param key crypto key for the cipher
95       * @param params the algorithm parameters
96       * @throws InvalidKeyException If key length is invalid
97       * @throws InvalidAlgorithmParameterException if IV length is wrong
98       */
99      @Override
100     public void init(int mode, Key key, AlgorithmParameterSpec params)
101             throws InvalidKeyException, InvalidAlgorithmParameterException {
102         Utils.checkNotNull(key);
103         Utils.checkNotNull(params);
104 
105         int cipherMode = OpenSsl.DECRYPT_MODE;
106         if (mode == Cipher.ENCRYPT_MODE) {
107             cipherMode = OpenSsl.ENCRYPT_MODE;
108         }
109         byte[] iv;
110         if (params instanceof IvParameterSpec) {
111             iv = ((IvParameterSpec) params).getIV();
112         } else {
113             // other AlgorithmParameterSpec such as GCMParameterSpec is not
114             // supported now.
115             throw new InvalidAlgorithmParameterException("Illegal parameters");
116         }
117         cipher.init(cipherMode, key.getEncoded(), iv);
118     }
119 
120     /**
121      * Continues a multiple-part encryption/decryption operation. The data is
122      * encrypted or decrypted, depending on how this cipher was initialized.
123      *
124      * @param inBuffer the input ByteBuffer
125      * @param outBuffer the output ByteBuffer
126      * @return int number of bytes stored in <code>output</code>
127      * @throws ShortBufferException if there is insufficient space in the output
128      *         buffer
129      */
130     @Override
131     public int update(ByteBuffer inBuffer, ByteBuffer outBuffer)
132             throws ShortBufferException {
133         return cipher.update(inBuffer, outBuffer);
134     }
135 
136     /**
137      * Continues a multiple-part encryption/decryption operation. The data is
138      * encrypted or decrypted, depending on how this cipher was initialized.
139      *
140      * @param input the input byte array
141      * @param inputOffset the offset in input where the input starts
142      * @param inputLen the input length
143      * @param output the byte array for the result
144      * @param outputOffset the offset in output where the result is stored
145      * @return the number of bytes stored in output
146      * @throws ShortBufferException if there is insufficient space in the output
147      *         byte array
148      */
149     @Override
150     public int update(byte[] input, int inputOffset, int inputLen,
151             byte[] output, int outputOffset) throws ShortBufferException {
152         return cipher
153                 .update(input, inputOffset, inputLen, output, outputOffset);
154     }
155 
156     /**
157      * Encrypts or decrypts data in a single-part operation, or finishes a
158      * multiple-part operation. The data is encrypted or decrypted, depending on
159      * how this cipher was initialized.
160      *
161      * @param inBuffer the input ByteBuffer
162      * @param outBuffer the output ByteBuffer
163      * @return int number of bytes stored in <code>output</code>
164      * @throws BadPaddingException if this cipher is in decryption mode, and
165      *         (un)padding has been requested, but the decrypted data is not
166      *         bounded by the appropriate padding bytes
167      * @throws IllegalBlockSizeException if this cipher is a block cipher, no
168      *         padding has been requested (only in encryption mode), and the
169      *         total input length of the data processed by this cipher is not a
170      *         multiple of block size; or if this encryption algorithm is unable
171      *         to process the input data provided.
172      * @throws ShortBufferException if the given output buffer is too small to
173      *         hold the result
174      */
175     @Override
176     public int doFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
177             throws ShortBufferException, IllegalBlockSizeException,
178             BadPaddingException {
179         int n = cipher.update(inBuffer, outBuffer);
180         return n + cipher.doFinal(outBuffer);
181     }
182 
183     /**
184      * Encrypts or decrypts data in a single-part operation, or finishes a
185      * multiple-part operation.
186      *
187      * @param input the input byte array
188      * @param inputOffset the offset in input where the input starts
189      * @param inputLen the input length
190      * @param output the byte array for the result
191      * @param outputOffset the offset in output where the result is stored
192      * @return the number of bytes stored in output
193      * @throws ShortBufferException if the given output byte array is too small
194      *         to hold the result
195      * @throws BadPaddingException if this cipher is in decryption mode, and
196      *         (un)padding has been requested, but the decrypted data is not
197      *         bounded by the appropriate padding bytes
198      * @throws IllegalBlockSizeException if this cipher is a block cipher, no
199      *         padding has been requested (only in encryption mode), and the
200      *         total input length of the data processed by this cipher is not a
201      *         multiple of block size; or if this encryption algorithm is unable
202      *         to process the input data provided.
203      */
204     @Override
205     public int doFinal(byte[] input, int inputOffset, int inputLen,
206             byte[] output, int outputOffset) throws ShortBufferException,
207             IllegalBlockSizeException, BadPaddingException {
208         int n = cipher.update(input, inputOffset, inputLen, output,
209                 outputOffset);
210         return n + cipher.doFinal(output, outputOffset + n);
211     }
212 
213     /**
214      * Closes the OpenSSL cipher. Clean the OpenSsl native context.
215      */
216     @Override
217     public void close() {
218         cipher.clean();
219     }
220 }