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,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.shiro.crypto.cipher;
20
21 import org.apache.shiro.crypto.CryptoException;
22 import org.apache.shiro.lang.util.ByteSource;
23
24 import java.io.InputStream;
25 import java.io.OutputStream;
26
27 /**
28 * A {@code CipherService} uses a cryptographic algorithm called a
29 * <a href="http://en.wikipedia.org/wiki/Cipher">Cipher</a> to convert an original input source using a {@code key} to
30 * an uninterpretable format. The resulting encrypted output is only able to be converted back to original form with
31 * a {@code key} as well. {@code CipherService}s can perform both encryption and decryption.
32 * <h2>Cipher Basics</h2>
33 * For what is known as <em>Symmetric</em> {@code Cipher}s, the {@code Key} used to encrypt the source is the same
34 * as (or trivially similar to) the {@code Key} used to decrypt it.
35 * <p/>
36 * For <em>Asymmetric</em> {@code Cipher}s, the encryption {@code Key} is not the same as the decryption {@code Key}.
37 * The most common type of Asymmetric Ciphers are based on what is called public/private key pairs:
38 * <p/>
39 * A <em>private</em> key is known only to a single party, and as its name implies, is supposed be kept very private
40 * and secure. A <em>public</em> key that is associated with the private key can be disseminated freely to anyone.
41 * Then data encrypted by the public key can only be decrypted by the private key and vice versa, but neither party
42 * need share their private key with anyone else. By not sharing a private key, you can guarantee no 3rd party can
43 * intercept the key and therefore use it to decrypt a message.
44 * <p/>
45 * This asymmetric key technology was created as a
46 * more secure alternative to symmetric ciphers that sometimes suffer from man-in-the-middle attacks since, for
47 * data shared between two parties, the same Key must also be shared and may be compromised.
48 * <p/>
49 * Note that a symmetric cipher is perfectly fine to use if you just want to encode data in a format no one else
50 * can understand and you never give away the key. Shiro uses a symmetric cipher when creating certain
51 * HTTP Cookies for example - because it is often undesirable to have user's identity stored in a plain-text cookie,
52 * that identity can be converted via a symmetric cipher. Since the the same exact Shiro application will receive
53 * the cookie, it can decrypt it via the same {@code Key} and there is no potential for discovery since that Key
54 * is never shared with anyone.
55 * <h2>{@code CipherService}s vs JDK {@link javax.crypto.Cipher Cipher}s</h2>
56 * Shiro {@code CipherService}s essentially do the same things as JDK {@link javax.crypto.Cipher Cipher}s, but in
57 * simpler and easier-to-use ways for most application developers. When thinking about encrypting and decrypting data
58 * in an application, most app developers want what a {@code CipherService} provides, rather than having to manage the
59 * lower-level intricacies of the JDK's {@code Cipher} API. Here are a few reasons why most people prefer
60 * {@code CipherService}s:
61 * <ul>
62 * <li><b>Stateless Methods</b> - {@code CipherService} method calls do not retain state between method invocations.
63 * JDK {@code Cipher} instances do retain state across invocations, requiring its end-users to manage the instance
64 * and its state themselves.</li>
65 * <li><b>Thread Safety</b> - {@code CipherService} instances are thread-safe inherently because no state is
66 * retained across method invocations. JDK {@code Cipher} instances retain state and cannot be used by multiple
67 * threads concurrently.</li>
68 * <li><b>Single Operation</b> - {@code CipherService} method calls are single operation methods: encryption or
69 * decryption in their entirety are done as a single method call. This is ideal for the large majority of developer
70 * needs where you have something unencrypted and just want it decrypted (or vice versa) in a single method call. In
71 * contrast, JDK {@code Cipher} instances can support encrypting/decrypting data in chunks over time (because it
72 * retains state), but this often introduces API clutter and confusion for most application developers.</li>
73 * <li><b>Type Safe</b> - There are {@code CipherService} implementations for different Cipher algorithms
74 * ({@code AesCipherService}, {@code BlowfishCipherService}, etc.). There is only one JDK {@code Cipher} class to
75 * represent all cipher algorithms/instances.
76 * <li><b>Simple Construction</b> - Because {@code CipherService} instances are type-safe, instantiating and using
77 * one is often as simple as calling the default constructor, for example, <code>new AesCipherService();</code>. The
78 * JDK {@code Cipher} class however requires using a procedural factory method with String arguments to indicate how
79 * the instance should be created. The String arguments themselves are somewhat cryptic and hard to
80 * understand unless you're a security expert. Shiro hides these details from you, but allows you to configure them
81 * if you want.</li>
82 * </ul>
83 *
84 * @see BlowfishCipherService
85 * @see AesCipherService
86 * @since 1.0
87 */
88 public interface CipherService {
89
90 /**
91 * Decrypts encrypted data via the specified cipher key and returns the original (pre-encrypted) data.
92 * Note that the key must be in a format understood by the CipherService implementation.
93 *
94 * @param encrypted the previously encrypted data to decrypt
95 * @param decryptionKey the cipher key used during decryption.
96 * @return a byte source representing the original form of the specified encrypted data.
97 * @throws CryptoException if there is an error during decryption
98 */
99 ByteSourceBroker decrypt(byte[] encrypted, byte[] decryptionKey) throws CryptoException;
100
101 /**
102 * Receives encrypted data from the given {@code InputStream}, decrypts it, and sends the resulting decrypted data
103 * to the given {@code OutputStream}.
104 * <p/>
105 * <b>NOTE:</b> This method <em>does NOT</em> flush or close either stream prior to returning - the caller must
106 * do so when they are finished with the streams. For example:
107 * <pre>
108 * try {
109 * InputStream in = ...
110 * OutputStream out = ...
111 * cipherService.decrypt(in, out, decryptionKey);
112 * } finally {
113 * if (in != null) {
114 * try {
115 * in.close();
116 * } catch (IOException ioe1) { ... log, trigger event, etc. }
117 * }
118 * if (out != null) {
119 * try {
120 * out.close();
121 * } catch (IOException ioe2) { ... log, trigger event, etc. }
122 * }
123 * }
124 * </pre>
125 *
126 * @param in the stream supplying the data to decrypt
127 * @param out the stream to send the decrypted data
128 * @param decryptionKey the cipher key to use for decryption
129 * @throws CryptoException if there is any problem during decryption.
130 */
131 void decrypt(InputStream in, OutputStream out, byte[] decryptionKey) throws CryptoException;
132
133 /**
134 * Encrypts data via the specified cipher key. Note that the key must be in a format understood by
135 * the {@code CipherService} implementation.
136 *
137 * @param raw the data to encrypt
138 * @param encryptionKey the cipher key used during encryption.
139 * @return a byte source with the encrypted representation of the specified raw data.
140 * @throws CryptoException if there is an error during encryption
141 */
142 ByteSource encrypt(byte[] raw, byte[] encryptionKey) throws CryptoException;
143
144 /**
145 * Receives the data from the given {@code InputStream}, encrypts it, and sends the resulting encrypted data to the
146 * given {@code OutputStream}.
147 * <p/>
148 * <b>NOTE:</b> This method <em>does NOT</em> flush or close either stream prior to returning - the caller must
149 * do so when they are finished with the streams. For example:
150 * <pre>
151 * try {
152 * InputStream in = ...
153 * OutputStream out = ...
154 * cipherService.encrypt(in, out, encryptionKey);
155 * } finally {
156 * if (in != null) {
157 * try {
158 * in.close();
159 * } catch (IOException ioe1) { ... log, trigger event, etc. }
160 * }
161 * if (out != null) {
162 * try {
163 * out.close();
164 * } catch (IOException ioe2) { ... log, trigger event, etc. }
165 * }
166 * }
167 * </pre>
168 *
169 * @param in the stream supplying the data to encrypt
170 * @param out the stream to send the encrypted data
171 * @param encryptionKey the cipher key to use for encryption
172 * @throws CryptoException if there is any problem during encryption.
173 */
174 void encrypt(InputStream in, OutputStream out, byte[] encryptionKey) throws CryptoException;
175
176 }