|
29 | 29 | import org.keyczar.util.Base64Coder;
|
30 | 30 |
|
31 | 31 | import java.nio.ByteBuffer;
|
| 32 | +import java.util.Collection; |
32 | 33 |
|
33 | 34 | /**
|
34 | 35 | * Crypters may both encrypt and decrypt data using sets of symmetric or private
|
@@ -78,7 +79,7 @@ public Crypter(String fileLocation) throws KeyczarException {
|
78 | 79 | public byte[] decrypt(byte[] input) throws KeyczarException {
|
79 | 80 | ByteBuffer output = ByteBuffer.allocate(input.length);
|
80 | 81 | decrypt(ByteBuffer.wrap(input), output);
|
81 |
| - output.reset(); |
| 82 | + output.rewind(); |
82 | 83 | byte[] outputBytes = new byte[output.remaining()];
|
83 | 84 | output.get(outputBytes);
|
84 | 85 | return outputBytes;
|
@@ -107,57 +108,91 @@ public void decrypt(ByteBuffer input, ByteBuffer output)
|
107 | 108 |
|
108 | 109 | byte[] hash = new byte[KEY_HASH_SIZE];
|
109 | 110 | inputCopy.get(hash);
|
110 |
| - KeyczarKey key = getKey(hash); |
111 |
| - if (key == null) { |
| 111 | + Collection<KeyczarKey> keys = getKey(hash); |
| 112 | + if (keys == null) { |
112 | 113 | throw new KeyNotFoundException(hash);
|
113 | 114 | }
|
114 | 115 |
|
115 | 116 | // The input to decrypt is now positioned at the start of the ciphertext
|
116 | 117 | inputCopy.mark();
|
117 |
| - |
118 |
| - DecryptingStream cryptStream = (DecryptingStream) key.getStream(); |
119 |
| - |
120 |
| - VerifyingStream verifyStream = cryptStream.getVerifyingStream(); |
121 |
| - if (inputCopy.remaining() < verifyStream.digestSize()) { |
122 |
| - throw new ShortCiphertextException(inputCopy.remaining()); |
| 118 | + int inputLimit = inputCopy.limit(); |
| 119 | + KeyczarException error = null; |
| 120 | + |
| 121 | + boolean collision = keys.size() > 1; |
| 122 | + |
| 123 | + for (KeyczarKey key : keys) { |
| 124 | + error = null; |
| 125 | + |
| 126 | + ByteBuffer tempBuffer = output; |
| 127 | + if (collision) { |
| 128 | + tempBuffer = ByteBuffer.allocate(output.capacity()); |
| 129 | + } |
| 130 | + |
| 131 | + DecryptingStream cryptStream = (DecryptingStream) key.getStream(); |
| 132 | + |
| 133 | + try { |
| 134 | + VerifyingStream verifyStream = cryptStream.getVerifyingStream(); |
| 135 | + if (inputCopy.remaining() < verifyStream.digestSize()) { |
| 136 | + throw new ShortCiphertextException(inputCopy.remaining()); |
| 137 | + } |
| 138 | + |
| 139 | + // Slice off the signature into another buffer |
| 140 | + inputCopy.position(inputCopy.limit() - verifyStream.digestSize()); |
| 141 | + ByteBuffer signature = inputCopy.slice(); |
| 142 | + |
| 143 | + // Reset the position of the input to start of the ciphertext |
| 144 | + inputCopy.reset(); |
| 145 | + inputCopy.limit(inputCopy.limit() - verifyStream.digestSize()); |
| 146 | + |
| 147 | + // Initialize the crypt stream. This may read an IV if any. |
| 148 | + cryptStream.initDecrypt(inputCopy); |
| 149 | + |
| 150 | + // Verify the header and IV if any |
| 151 | + ByteBuffer headerAndIvToVerify = input.asReadOnlyBuffer(); |
| 152 | + headerAndIvToVerify.limit(inputCopy.position()); |
| 153 | + verifyStream.initVerify(); |
| 154 | + verifyStream.updateVerify(headerAndIvToVerify); |
| 155 | + |
| 156 | + tempBuffer.mark(); |
| 157 | + // This will process large input in chunks, rather than all at once. This |
| 158 | + // avoids making two passes through memory. |
| 159 | + while (inputCopy.remaining() > DECRYPT_CHUNK_SIZE) { |
| 160 | + ByteBuffer ciphertextChunk = inputCopy.slice(); |
| 161 | + ciphertextChunk.limit(DECRYPT_CHUNK_SIZE); |
| 162 | + cryptStream.updateDecrypt(ciphertextChunk, output); |
| 163 | + ciphertextChunk.rewind(); |
| 164 | + verifyStream.updateVerify(ciphertextChunk); |
| 165 | + inputCopy.position(inputCopy.position() + DECRYPT_CHUNK_SIZE); |
| 166 | + } |
| 167 | + int lastBlock = inputCopy.position(); |
| 168 | + verifyStream.updateVerify(inputCopy); |
| 169 | + if (!verifyStream.verify(signature)) { |
| 170 | + throw new InvalidSignatureException(); |
| 171 | + } |
| 172 | + inputCopy.position(lastBlock); |
| 173 | + cryptStream.doFinalDecrypt(inputCopy, tempBuffer); |
| 174 | + tempBuffer.limit(tempBuffer.position()); |
| 175 | + if (collision) { |
| 176 | + //Success copy to final output buffer |
| 177 | + tempBuffer.rewind(); |
| 178 | + output.put(tempBuffer); |
| 179 | + output.limit(output.position()); |
| 180 | + } |
| 181 | + return; |
| 182 | + } catch (KeyczarException e) { |
| 183 | + LOG.debug(e.getMessage(), e); |
| 184 | + error = e; |
| 185 | + } catch (RuntimeException e) { |
| 186 | + LOG.debug(e.getMessage(), e); |
| 187 | + error = new InvalidSignatureException(); |
| 188 | + } finally { |
| 189 | + inputCopy.reset(); |
| 190 | + inputCopy.limit(inputLimit); |
| 191 | + } |
123 | 192 | }
|
124 |
| - |
125 |
| - // Slice off the signature into another buffer |
126 |
| - inputCopy.position(inputCopy.limit() - verifyStream.digestSize()); |
127 |
| - ByteBuffer signature = inputCopy.slice(); |
128 |
| - |
129 |
| - // Reset the position of the input to start of the ciphertext |
130 |
| - inputCopy.reset(); |
131 |
| - inputCopy.limit(inputCopy.limit() - verifyStream.digestSize()); |
132 |
| - |
133 |
| - // Initialize the crypt stream. This may read an IV if any. |
134 |
| - cryptStream.initDecrypt(inputCopy); |
135 |
| - |
136 |
| - // Verify the header and IV if any |
137 |
| - ByteBuffer headerAndIvToVerify = input.asReadOnlyBuffer(); |
138 |
| - headerAndIvToVerify.limit(inputCopy.position()); |
139 |
| - verifyStream.initVerify(); |
140 |
| - verifyStream.updateVerify(headerAndIvToVerify); |
141 |
| - |
142 |
| - output.mark(); |
143 |
| - // This will process large input in chunks, rather than all at once. This |
144 |
| - // avoids making two passes through memory. |
145 |
| - while (inputCopy.remaining() > DECRYPT_CHUNK_SIZE) { |
146 |
| - ByteBuffer ciphertextChunk = inputCopy.slice(); |
147 |
| - ciphertextChunk.limit(DECRYPT_CHUNK_SIZE); |
148 |
| - cryptStream.updateDecrypt(ciphertextChunk, output); |
149 |
| - ciphertextChunk.rewind(); |
150 |
| - verifyStream.updateVerify(ciphertextChunk); |
151 |
| - inputCopy.position(inputCopy.position() + DECRYPT_CHUNK_SIZE); |
152 |
| - } |
153 |
| - inputCopy.mark(); |
154 |
| - verifyStream.updateVerify(inputCopy); |
155 |
| - if (!verifyStream.verify(signature)) { |
156 |
| - throw new InvalidSignatureException(); |
| 193 | + if (error != null) { |
| 194 | + throw error; |
157 | 195 | }
|
158 |
| - inputCopy.reset(); |
159 |
| - cryptStream.doFinalDecrypt(inputCopy, output); |
160 |
| - output.limit(output.position()); |
161 | 196 | }
|
162 | 197 |
|
163 | 198 | /**
|
|
0 commit comments