|
| 1 | +package org.cryptomator.siv; |
| 2 | + |
| 3 | +import javax.crypto.AEADBadTagException; |
| 4 | +import javax.crypto.IllegalBlockSizeException; |
| 5 | +import javax.crypto.SecretKey; |
| 6 | +import java.util.Arrays; |
| 7 | + |
| 8 | +/** |
| 9 | + * Implements the RFC 5297 SIV mode. |
| 10 | + */ |
| 11 | +@Deprecated |
| 12 | +public final class SivMode { |
| 13 | + |
| 14 | + /** |
| 15 | + * Creates an AES-SIV instance using JCE's cipher implementation, which should normally be the best choice.<br> |
| 16 | + */ |
| 17 | + public SivMode() { |
| 18 | + } |
| 19 | + |
| 20 | + /** |
| 21 | + * Convenience method using a single 256, 384, or 512 bits key. This is just a wrapper for {@link #encrypt(byte[], byte[], byte[], byte[]...)}. |
| 22 | + * @param key Combined key, which is split in half. |
| 23 | + * @param plaintext Your plaintext, which shall be encrypted. |
| 24 | + * @param associatedData Optional associated data, which gets authenticated but not encrypted. |
| 25 | + * @return IV + Ciphertext as a concatenated byte array. |
| 26 | + */ |
| 27 | + public byte[] encrypt(SecretKey key, byte[] plaintext, byte[]... associatedData) { |
| 28 | + final byte[] keyBytes = key.getEncoded(); |
| 29 | + if (keyBytes == null) { |
| 30 | + throw new IllegalArgumentException("Can't get bytes of given key."); |
| 31 | + } |
| 32 | + try { |
| 33 | + return new SivEngine(keyBytes).encrypt(plaintext, associatedData); |
| 34 | + } finally { |
| 35 | + Arrays.fill(keyBytes, (byte) 0); |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * Convenience method, if you are using the javax.crypto API. This is just a wrapper for {@link #encrypt(byte[], byte[], byte[], byte[]...)}. |
| 41 | + * |
| 42 | + * @param ctrKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 43 | + * @param macKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 44 | + * @param plaintext Your plaintext, which shall be encrypted. |
| 45 | + * @param associatedData Optional associated data, which gets authenticated but not encrypted. |
| 46 | + * @return IV + Ciphertext as a concatenated byte array. |
| 47 | + * @throws IllegalArgumentException if keys are invalid or {@link SecretKey#getEncoded()} is not supported. |
| 48 | + */ |
| 49 | + public byte[] encrypt(SecretKey ctrKey, SecretKey macKey, byte[] plaintext, byte[]... associatedData) { |
| 50 | + final byte[] ctrKeyBytes = ctrKey.getEncoded(); |
| 51 | + final byte[] macKeyBytes = macKey.getEncoded(); |
| 52 | + if (ctrKeyBytes == null || macKeyBytes == null) { |
| 53 | + throw new IllegalArgumentException("Can't get bytes of given key."); |
| 54 | + } |
| 55 | + try { |
| 56 | + return encrypt(ctrKeyBytes, macKeyBytes, plaintext, associatedData); |
| 57 | + } finally { |
| 58 | + Arrays.fill(ctrKeyBytes, (byte) 0); |
| 59 | + Arrays.fill(macKeyBytes, (byte) 0); |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + /** |
| 64 | + * Encrypts plaintext using SIV mode. A block cipher defined by the constructor is being used.<br> |
| 65 | + * |
| 66 | + * @param ctrKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 67 | + * @param macKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 68 | + * @param plaintext Your plaintext, which shall be encrypted. |
| 69 | + * @param associatedData Optional associated data, which gets authenticated but not encrypted. |
| 70 | + * @return IV + Ciphertext as a concatenated byte array. |
| 71 | + * @throws IllegalArgumentException if the either of the two keys is of invalid length for the used {@link BlockCipher}. |
| 72 | + */ |
| 73 | + public byte[] encrypt(byte[] ctrKey, byte[] macKey, byte[] plaintext, byte[]... associatedData) { |
| 74 | + byte[] combinedKey = new byte[ctrKey.length + macKey.length]; |
| 75 | + try { |
| 76 | + System.arraycopy(macKey, 0, combinedKey, 0, macKey.length); |
| 77 | + System.arraycopy(ctrKey, 0, combinedKey, macKey.length, ctrKey.length); |
| 78 | + return new SivEngine(combinedKey).encrypt(plaintext, associatedData); |
| 79 | + } finally { |
| 80 | + Arrays.fill(combinedKey, (byte) 0); |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + /** |
| 85 | + * Convenience method using a single 256, 384, or 512 bits key. This is just a wrapper for {@link #decrypt(byte[], byte[], byte[], byte[]...)}. |
| 86 | + * @param key Combined key, which is split in half. |
| 87 | + * @param ciphertext Your cipehrtext, which shall be decrypted. |
| 88 | + * @param associatedData Optional associated data, which gets authenticated but not encrypted. |
| 89 | + * @return Plaintext byte array. |
| 90 | + * @throws IllegalArgumentException If keys are invalid. |
| 91 | + * @throws UnauthenticCiphertextException If the authentication failed, e.g. because ciphertext and/or associatedData are corrupted. |
| 92 | + * @throws IllegalBlockSizeException If the provided ciphertext is of invalid length. |
| 93 | + */ |
| 94 | + public byte[] decrypt(SecretKey key, byte[] ciphertext, byte[]... associatedData) throws UnauthenticCiphertextException, IllegalBlockSizeException { |
| 95 | + final byte[] keyBytes = key.getEncoded(); |
| 96 | + if (keyBytes == null) { |
| 97 | + throw new IllegalArgumentException("Can't get bytes of given key."); |
| 98 | + } |
| 99 | + try { |
| 100 | + return new SivEngine(keyBytes).decrypt(ciphertext, associatedData); |
| 101 | + } catch (AEADBadTagException e) { |
| 102 | + throw new UnauthenticCiphertextException("authentication in SIV decryption failed"); |
| 103 | + } finally { |
| 104 | + Arrays.fill(keyBytes, (byte) 0); |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + /** |
| 109 | + * Convenience method, if you are using the javax.crypto API. This is just a wrapper for {@link #decrypt(byte[], byte[], byte[], byte[]...)}. |
| 110 | + * |
| 111 | + * @param ctrKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 112 | + * @param macKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 113 | + * @param ciphertext Your cipehrtext, which shall be decrypted. |
| 114 | + * @param associatedData Optional associated data, which needs to be authenticated during decryption. |
| 115 | + * @return Plaintext byte array. |
| 116 | + * @throws IllegalArgumentException If keys are invalid or {@link SecretKey#getEncoded()} is not supported. |
| 117 | + * @throws UnauthenticCiphertextException If the authentication failed, e.g. because ciphertext and/or associatedData are corrupted. |
| 118 | + * @throws IllegalBlockSizeException If the provided ciphertext is of invalid length. |
| 119 | + */ |
| 120 | + public byte[] decrypt(SecretKey ctrKey, SecretKey macKey, byte[] ciphertext, byte[]... associatedData) throws UnauthenticCiphertextException, IllegalBlockSizeException { |
| 121 | + final byte[] ctrKeyBytes = ctrKey.getEncoded(); |
| 122 | + final byte[] macKeyBytes = macKey.getEncoded(); |
| 123 | + if (ctrKeyBytes == null || macKeyBytes == null) { |
| 124 | + throw new IllegalArgumentException("Can't get bytes of given key."); |
| 125 | + } |
| 126 | + try { |
| 127 | + return decrypt(ctrKeyBytes, macKeyBytes, ciphertext, associatedData); |
| 128 | + } finally { |
| 129 | + Arrays.fill(ctrKeyBytes, (byte) 0); |
| 130 | + Arrays.fill(macKeyBytes, (byte) 0); |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + /** |
| 135 | + * Decrypts ciphertext using SIV mode. A block cipher defined by the constructor is being used.<br> |
| 136 | + * |
| 137 | + * @param ctrKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 138 | + * @param macKey SIV mode requires two separate keys. You can use one long key, which is split in half. See <a href="https://tools.ietf.org/html/rfc5297#section-2.2">RFC 5297 Section 2.2</a> |
| 139 | + * @param ciphertext Your ciphertext, which shall be encrypted. |
| 140 | + * @param associatedData Optional associated data, which needs to be authenticated during decryption. |
| 141 | + * @return Plaintext byte array. |
| 142 | + * @throws IllegalArgumentException If the either of the two keys is of invalid length. |
| 143 | + * @throws UnauthenticCiphertextException If the authentication failed, e.g. because ciphertext and/or associatedData are corrupted. |
| 144 | + * @throws IllegalBlockSizeException If the provided ciphertext is of invalid length. |
| 145 | + */ |
| 146 | + public byte[] decrypt(byte[] ctrKey, byte[] macKey, byte[] ciphertext, byte[]... associatedData) throws UnauthenticCiphertextException, IllegalBlockSizeException { |
| 147 | + byte[] combinedKey = new byte[ctrKey.length + macKey.length]; |
| 148 | + try { |
| 149 | + System.arraycopy(macKey, 0, combinedKey, 0, macKey.length); |
| 150 | + System.arraycopy(ctrKey, 0, combinedKey, macKey.length, ctrKey.length); |
| 151 | + return new SivEngine(combinedKey).decrypt(ciphertext, associatedData); |
| 152 | + } catch (AEADBadTagException e) { |
| 153 | + throw new UnauthenticCiphertextException("authentication in SIV decryption failed"); |
| 154 | + } finally { |
| 155 | + Arrays.fill(combinedKey, (byte) 0); |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | +} |
0 commit comments