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