All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.tommyettinger.random.cipher.SpeckCipher Maven / Gradle / Ivy

There is a newer version: 0.6.1
Show newest version
package com.github.tommyettinger.random.cipher;

import java.nio.ByteBuffer;

/**
 * An implementation of the Speck Cipher that can encrypt
 * and decrypt using either CBC or CTR modes. Speck is designed to be small and fast when implemented in software.
 * This does not extend {@code javax.crypto.Cipher} because that isn't possible in a pure Java library, to my knowledge.
 * 
* I have very little faith in my implementation's accuracy, and even an accurate implementation would have been * specified by The United States of America's NSA, making it inherently untrustworthy. It should be fast, though, * and strong enough to keep small-time crooks out of encrypted files. Big-time crooks (nation-states) should be * assumed to already have anything they want that was encrypted with this. *
* This uses a block size of 128 bits and a key size of 256 bits. *
* The implementation here is based on m2mi's open_speck C code, * which is licensed under Apache 2.0. Though the m2mi implementation seems to use some form of PKCS#7 for padding, it * encrypts the last block but doesn't decrypt it, so I think it may only work when a full block of padding is written, * validated and ignored. That is, if it works at all! I haven't been able to test m2mi's implementation, but this * code has been tested some in this repo. This version uses zero-padding instead of PKCS#7, and works even if a * partial block is all there is in the plaintext. When encrypting with CBC mode, the ciphertext array may need to be * larger than the plaintext array; use {@link #newPaddedArray(long[])} or {@link #newPaddedArray(byte[])} to get an * array of the right size. This isn't required for CTR mode. */ public final class SpeckCipher { private SpeckCipher() { } private static long fromBytes(byte[] bytes, int index) { long r = 0; if(bytes.length > index) { switch (bytes.length - index) { default: r = (bytes[index+7] & 255L) | (bytes[index+6] & 255L) << 8 | (bytes[index+5] & 255L) << 16 | (bytes[index+4] & 255L) << 24 | (bytes[index+3] & 255L) << 32 | (bytes[index+2] & 255L) << 40 | (bytes[index+1] & 255L) << 48 | (bytes[index ] & 255L) << 56; break; case 7: r |= (bytes[index+6] & 255L) << 8; case 6: r |= (bytes[index+5] & 255L) << 16; case 5: r |= (bytes[index+4] & 255L) << 24; case 4: r |= (bytes[index+3] & 255L) << 32; case 3: r |= (bytes[index+2] & 255L) << 40; case 2: r |= (bytes[index+1] & 255L) << 48; case 1: r |= (bytes[index ] & 255L) << 56; } } return r; } private static void intoBytes(byte[] bytes, int index, long data) { if(bytes.length > index) { switch (bytes.length - index) { default: bytes[index + 7] = (byte) data; case 7: bytes[index + 6] = (byte) (data >>> 8); case 6: bytes[index + 5] = (byte) (data >>> 16); case 5: bytes[index + 4] = (byte) (data >>> 24); case 4: bytes[index + 3] = (byte) (data >>> 32); case 3: bytes[index + 2] = (byte) (data >>> 40); case 2: bytes[index + 1] = (byte) (data >>> 48); case 1: bytes[index ] = (byte) (data >>> 56); } } } private static void xorIntoBytes(byte[] bytes, int index, long data) { if(bytes.length > index) { switch (bytes.length - index) { default: bytes[index + 7] ^= (byte) data; case 7: bytes[index + 6] ^= (byte) (data >>> 8); case 6: bytes[index + 5] ^= (byte) (data >>> 16); case 5: bytes[index + 4] ^= (byte) (data >>> 24); case 4: bytes[index + 3] ^= (byte) (data >>> 32); case 3: bytes[index + 2] ^= (byte) (data >>> 40); case 2: bytes[index + 1] ^= (byte) (data >>> 48); case 1: bytes[index ] ^= (byte) (data >>> 56); } } } private static void xorBytePairs(byte[] into, int indexInto, byte[] with, int indexWith, int length) { for (int x = 0, n = Math.min(length, Math.min(into.length - indexInto, with.length - indexWith)); x < n; x++, indexInto++, indexWith++) { into[indexInto] ^= with[indexWith]; } } private static void xorIntoByteBuffer(ByteBuffer bytes, int index, long data) { switch (bytes.limit() - index) { default: bytes.putLong(index, bytes.getLong(index) ^ data); break; case 7: bytes.putInt(index, bytes.getInt(index) ^ (int) data); bytes.putShort(index + 4, (short) (bytes.getShort(index + 4) ^ data >>> 32)); bytes.put(index + 6, (byte) (bytes.get(index + 6) ^ data >>> 48)); break; case 6: bytes.putInt(index, bytes.getInt(index) ^ (int) data); bytes.putShort(index + 4, (short) (bytes.getShort(index + 4) ^ data >>> 32)); break; case 5: bytes.putInt(index, bytes.getInt(index) ^ (int) data); bytes.put(index + 4, (byte) (bytes.get(index + 4) ^ data >>> 32)); break; case 4: bytes.putInt(index, bytes.getInt(index) ^ (int) data); break; case 3: bytes.putShort(index, (short) (bytes.getShort(index) ^ data)); bytes.put(index + 2, (byte) (bytes.get(index + 2) ^ data >>> 16)); break; case 2: bytes.putShort(index, (short) (bytes.getShort(index) ^ data)); break; case 1: bytes.put(index, (byte) (bytes.get(index) ^ data)); break; } } /** * Copies {@code data} into a new long array that will be at least as long as data, padded with zeroes * so that it meets a length that is a multiple of 2, if necessary. If data is null, this returns a new * long array with length 2. *
* This is typically used to ensure the ciphertext array is long enough to hold the data assigned to it. * It is only needed for the ciphertext written to by * {@link #encryptCBC(long, long, long, long, long, long, long[], int, long[], int, int)} (CTR doesn't need it). * * @param data a long array to copy, potentially including padding in the copy * @return a long array with a length that is a multiple of 2 */ public static long[] newPaddedArray(long[] data) { if(data == null) return new long[2]; return new long[data.length + 1 & -2]; } /** * Copies {@code data} into a new byte array that will be at least as long as data, padded with zeroes * so that it meets a length that is a multiple of 16, if necessary. If data is null, this returns a new * byte array with length 16. *
* This is typically used to ensure the ciphertext array is long enough to hold the data assigned to it. * It is only needed for the ciphertext written to by * {@link #encryptCBC(long, long, long, long, long, long, byte[], int, byte[], int, int)} (CTR doesn't need it). * * @param data a byte array to copy, potentially including padding in the copy * @return a byte array with a length that is a multiple of 16 */ public static byte[] newPaddedArray(byte[] data) { if(data == null) return new byte[16]; return new byte[data.length + 15 & -16]; } /** * Given a 256-bit key as four long values, this grows that initial key into a 2176-bit expanded key (a * {@code long[34]}). This uses 34 rounds of the primary algorithm used by Speck. * Used by {@link #encryptCBC}, {@link #encryptCTR}, {@link #decryptCBC}, and {@link #decryptCTR} internally. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @return a 34-item long array that should, of course, be kept secret to be used cryptographically */ public static long[] expandKey(long k1, long k2, long k3, long k4) { long tk0 = k4, tk1 = k3, tk2 = k2, tk3 = k1; long[] k = new long[34]; k[0] = k4; // corresponds to 34 rounds for (int i = 0, c = 0; i < 11; i++) { tk1 = (tk1 << 56 | tk1 >>> 8) + tk0 ^ c; tk0 = (tk0 << 3 | tk0 >>> 61) ^ tk1; ++c; k[c] = tk0; tk2 = (tk2 << 56 | tk2 >>> 8) + tk0 ^ c; tk0 = (tk0 << 3 | tk0 >>> 61) ^ tk2; ++c; k[c] = tk0; tk3 = (tk3 << 56 | tk3 >>> 8) + tk0 ^ c; tk0 = (tk0 << 3 | tk0 >>> 61) ^ tk3; ++c; k[c] = tk0; } return k; } /** * A usually-internal encryption step. You should use either CBC or CTR mode to actually encrypt a piece of * plaintext, with {@link #encryptCBC(long, long, long, long, long, long, long[], int, long[], int, int)} or * {@link #encryptCTR(long, long, long, long, long, long[], int, long[], int, int)}. * @param key an expanded key, as produced by {@link #expandKey(long, long, long, long)} * @param last0 the first half of the previous result, or the first IV if there was no previous result * @param last1 the last half of the previous result, or the second IV if there was no previous result * @param plaintext the plaintext array, as long items * @param plainOffset the index to start reading from in plaintext * @param ciphertext the ciphertext array, as long items that will be written to; {@link #newPaddedArray(long[]) may need to be padded} * @param cipherOffset the index to start writing to in ciphertext */ public static void encrypt(long[] key, long last0, long last1, long[] plaintext, int plainOffset, long[] ciphertext, int cipherOffset) { long b0, b1; if(plaintext == null){ b0 = last0; b1 = last1; } else if(plaintext.length - plainOffset >= 2) { b1 = plaintext[plainOffset] ^ last0; b0 = plaintext[plainOffset + 1] ^ last1; } else if(plaintext.length - plainOffset >= 1) { b0 = last1; b1 = plaintext[plainOffset] ^ last0; } else { b0 = last1; b1 = last0; } for (int i = 0; i < 34; i++) { b1 = (b1 << 56 | b1 >>> 8) + b0 ^ key[i]; b0 = (b0 << 3 | b0 >>> 61) ^ b1; } ciphertext[cipherOffset] = b1; if(cipherOffset + 1 < ciphertext.length) ciphertext[cipherOffset + 1] = b0; } /** * A usually-internal encryption step. You should use either CBC or CTR mode to actually encrypt a piece of * plaintext, with {@link #encryptCBC(long, long, long, long, long, long, byte[], int, byte[], int, int)} or * {@link #encryptCTR(long, long, long, long, long, byte[], int, byte[], int, int)}. * @param key an expanded key, as produced by {@link #expandKey(long, long, long, long)} * @param last0 the first half of the previous result, or the first IV if there was no previous result * @param last1 the last half of the previous result, or the second IV if there was no previous result * @param plaintext the plaintext array, as byte items * @param plainOffset the index to start reading from in plaintext * @param ciphertext the ciphertext array, as byte items that will be written to; {@link #newPaddedArray(byte[]) may need to be padded} * @param cipherOffset the index to start writing to in ciphertext */ public static void encrypt(long[] key, long last0, long last1, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset) { long b0, b1; if(plaintext == null){ b0 = last0; b1 = last1; } else { b1 = fromBytes(plaintext, plainOffset) ^ last0; b0 = fromBytes(plaintext, plainOffset + 8) ^ last1; } for (int i = 0; i < 34; i++) { b1 = (b1 << 56 | b1 >>> 8) + b0 ^ key[i]; b0 = (b0 << 3 | b0 >>> 61) ^ b1; } intoBytes(ciphertext, cipherOffset, b1); intoBytes(ciphertext, cipherOffset + 8, b0); } /** * A usually-internal encryption step. You should use either CBC or CTR mode to actually encrypt a piece of * plaintext, with {@link #encryptCBC(long, long, long, long, long, long, byte[], int, byte[], int, int)} or * {@link #encryptCTR(long, long, long, long, long, byte[], int, byte[], int, int)}. * @param key an expanded key, as produced by {@link #expandKey(long, long, long, long)} * @param iv0 the first IV * @param iv1 the second IV * @param plaintext the plaintext array, as byte items; will be modified * @param plainOffset the index to start writing to (with XOR) in plaintext */ public static void encryptWithXor(long[] key, long iv0, long iv1, byte[] plaintext, int plainOffset) { long b0 = iv0, b1 = iv1; for (int i = 0; i < 34; i++) { b1 = (b1 << 56 | b1 >>> 8) + b0 ^ key[i]; b0 = (b0 << 3 | b0 >>> 61) ^ b1; } xorIntoBytes(plaintext, plainOffset, b1); xorIntoBytes(plaintext, plainOffset + 8, b0); } /** * A usually-internal encryption step. You should use either CBC or CTR mode to actually encrypt a piece of * plaintext, with {@link #encryptCBC(long, long, long, long, long, long, byte[], int, byte[], int, int)} or * {@link #encryptCTR(long, long, long, long, long, byte[], int, byte[], int, int)}. * @param key an expanded key, as produced by {@link #expandKey(long, long, long, long)} * @param iv0 the first IV * @param iv1 the second IV * @param plaintext the plaintext array, as byte items; will be modified * @param plainOffset the index to start writing to (with XOR) in plaintext */ public static void encryptWithXor(long[] key, long iv0, long iv1, ByteBuffer plaintext, int plainOffset) { long b0 = iv0, b1 = iv1; for (int i = 0; i < 34; i++) { b1 = (b1 << 56 | b1 >>> 8) + b0 ^ key[i]; b0 = (b0 << 3 | b0 >>> 61) ^ b1; } xorIntoByteBuffer(plaintext, plainOffset, b1); xorIntoByteBuffer(plaintext, plainOffset + 8, b0); } /** * A usually-internal decryption step. You should use either CBC or CTR mode to actually decrypt a piece of * plaintext, with {@link #decryptCBC(long, long, long, long, long, long, long[], int, long[], int, int)} or * {@link #decryptCTR(long, long, long, long, long, long[], int, long[], int, int)}. * @param key an expanded key, as produced by {@link #expandKey(long, long, long, long)} * @param plaintext the plaintext array, as long items that will be written to * @param plainOffset the index to start writing to in plaintext * @param ciphertext the ciphertext array, as long items * @param cipherOffset the index to start reading from in ciphertext */ public static void decrypt(long[] key, long[] plaintext, int plainOffset, long[] ciphertext, int cipherOffset) { long b0, b1, item; b1 = ciphertext[cipherOffset]; b0 = ciphertext[cipherOffset + 1]; for (int i = 33; i >= 0; i--) { item = b0 ^ b1; b0 = (item << 61 | item >>> 3); item = (b1 ^ key[i]) - b0; b1 = (item << 8 | item >>> 56); } plaintext[plainOffset] = b1; if(plainOffset + 1 < plaintext.length) plaintext[plainOffset + 1] = b0; } /** * A usually-internal decryption step. You should use either CBC or CTR mode to actually decrypt a piece of * plaintext, with {@link #decryptCBC(long, long, long, long, long, long, byte[], int, byte[], int, int)} or * {@link #decryptCTR(long, long, long, long, long, byte[], int, byte[], int, int)}. * @param key an expanded key, as produced by {@link #expandKey(long, long, long, long)} * @param plaintext the plaintext array, as byte items that will be written to * @param plainOffset the index to start writing to in plaintext * @param ciphertext the ciphertext array, as byte items * @param cipherOffset the index to start reading from in ciphertext */ public static void decrypt(long[] key, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset) { long b0, b1, item; b1 = fromBytes(ciphertext, cipherOffset); b0 = fromBytes(ciphertext, cipherOffset + 8); for (int i = 33; i >= 0; i--) { item = b0 ^ b1; b0 = (item << 61 | item >>> 3); item = (b1 ^ key[i]) - b0; b1 = (item << 8 | item >>> 56); } intoBytes(plaintext, plainOffset, b1); intoBytes(plaintext, plainOffset + 8, b0); } /** * One of the main ways here to encrypt a "plaintext" long array and get back a coded "ciphertext" long array. * This takes four {@code long}s as its key (256-bits), and also requires two unique (never used again) longs * as IVs. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate IVs, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless IVs are requested for years from one generator, so it is a good * option to produce IVs (using two DistinctRandom generators also works, with one for each IV). The rest of the * arguments are about the data being encrypted. The plaintext is the long array to encrypt; it will not be * modified here. The plainOffset is which index in plaintext to start reading from. The ciphertext will be written * to, should usually be empty at the start (though it doesn't need to be), and must be padded as by * {@link #newPaddedArray(long[])}. The cipheroffset is which index to start writing to in ciphertext. Lastly, the * textLength is how many long items to encrypt from plaintext; this can be less than plaintext's length. *
* This uses CBC mode, so it takes two IVs instead of how CTR mode takes one nonce. If the IVs aren't sufficiently * random, this produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, though this isn't * clear yet. CTR mode doesn't need its ciphertext to have padding. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param iv1 a long that must never be reused as iv1 again under the same key; needed to decrypt * @param iv2 a long that must never be reused as iv2 again under the same key; needed to decrypt * @param plaintext the long array to encrypt; will not be modified * @param plainOffset which index to start reading from plaintext * @param ciphertext the long array to write encrypted data to; will be modified, and should be padded * @param cipherOffset which index to start writing to in ciphertext * @param textLength how many long items to read and encrypt from plaintext * @return ciphertext, after modifications */ public static long[] encryptCBC(long k1, long k2, long k3, long k4, long iv1, long iv2, long[] plaintext, int plainOffset, long[] ciphertext, int cipherOffset, int textLength) { int blocks = textLength + 1 >>> 1, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long last0 = iv2, last1 = iv1; do { encrypt(kx, last0, last1, plaintext, plainOffset, ciphertext, cipherOffset); last0 = ciphertext[cipherOffset]; last1 = ciphertext[cipherOffset+1]; plainOffset+=2; cipherOffset+=2; i++; } while(i < blocks); return ciphertext; } /** * One of the main ways here to encrypt a "plaintext" byte array and get back a coded "ciphertext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires two unique (never used again) longs * as IVs. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate IVs, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless IVs are requested for years from one generator, so it is a good * option to produce IVs (using two DistinctRandom generators also works, with one for each IV). The rest of the * arguments are about the data being encrypted. The plaintext is the byte array to encrypt; it will not be * modified here. The plainOffset is which index in plaintext to start reading from. The ciphertext will be written * to, should usually be empty at the start (though it doesn't need to be), and must be padded as by * {@link #newPaddedArray(byte[])}. The cipheroffset is which index to start writing to in ciphertext. Lastly, the * textLength is how many byte items to encrypt from plaintext; this can be less than plaintext's length. *
* This uses CBC mode, so it takes two IVs instead of how CTR mode takes one nonce. If the IVs aren't sufficiently * random, this produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, though this isn't * clear yet. CTR mode doesn't need its ciphertext to have padding. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param iv1 a long that must never be reused as iv1 again under the same key; needed to decrypt * @param iv2 a long that must never be reused as iv2 again under the same key; needed to decrypt * @param plaintext the byte array to encrypt; will not be modified * @param plainOffset which index to start reading from plaintext * @param ciphertext the byte array to write encrypted data to; will be modified, and should be padded * @param cipherOffset which index to start writing to in ciphertext * @param textLength how many byte items to read and encrypt from plaintext * @return ciphertext, after modifications */ public static byte[] encryptCBC(long k1, long k2, long k3, long k4, long iv1, long iv2, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset, int textLength) { int blocks = textLength + 15 >>> 4, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long last0 = iv2, last1 = iv1; do { encrypt(kx, last0, last1, plaintext, plainOffset, ciphertext, cipherOffset); last0 = fromBytes(ciphertext, cipherOffset); last1 = fromBytes(ciphertext, cipherOffset + 8); plainOffset+=16; cipherOffset+=16; i++; } while(i < blocks); return ciphertext; } /** * One of the main ways here to decrypt a coded "ciphertext" long array and get back the original "plaintext" * long array from before {@link #encryptCBC(long, long, long, long, long, long, long[], int, long[], int, int)} * was called. * This takes four {@code long}s as its key (256-bits), and also requires two unique (never used again) longs * as IVs. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate IVs, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless IVs are requested for years from one generator, so it is a good * option to produce IVs (using two DistinctRandom generators also works, with one for each IV). The rest of the * arguments are about the data being encrypted. The plaintext is the long array to receive decrypted data; it will * be modified, but doesn't have size restrictions. The plainOffset is which index in plaintext to start writing to. * The ciphertext will only be read from here, and should start with the output of encryptCBC(). The cipheroffset is * which index to start reading from in ciphertext. Lastly, the textLength is how many long items to decrypt from * ciphertext; this must be at least equal to plaintext's length. *
* This uses CBC mode, so it takes two IVs instead of how CTR mode takes one nonce. If the IVs aren't sufficiently * random, this produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, though this isn't * clear yet. CTR mode doesn't need its ciphertext to have padding. CBC mode requires textLength to be a multiple * of 2 (16 bytes) when decrypting (usually guaranteed by padding). * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param iv1 a long that was used as iv1 to encrypt this specific data * @param iv2 a long that was used as iv2 to encrypt this specific data * @param plaintext the long array to write to * @param plainOffset which index to start writing to in plaintext * @param ciphertext the long array to read coded data from * @param cipherOffset which index to start reading from in ciphertext * @param textLength how many long items to read from ciphertext * @return plaintext, after modifications */ public static long[] decryptCBC(long k1, long k2, long k3, long k4, long iv1, long iv2, long[] plaintext, int plainOffset, long[] ciphertext, int cipherOffset, int textLength) { int blocks = textLength + 1 >>> 1, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long last0 = iv2, last1 = iv1; do { decrypt(kx, plaintext, plainOffset, ciphertext, cipherOffset); plaintext[plainOffset] ^= last0; if(plainOffset + 1 < textLength) plaintext[plainOffset + 1] ^= last1; last0 = ciphertext[cipherOffset]; last1 = ciphertext[cipherOffset + 1]; plainOffset += 2; cipherOffset += 2; i++; } while (i < blocks); return plaintext; } /** * One of the main ways here to encrypt a "plaintext" byte array and get back a coded "ciphertext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being encrypted. The plaintext is the * byte array to encrypt; it will not be modified here. The plainOffset is which index in plaintext to start reading * from. The ciphertext is the byte array that will be written to, and should usually be empty at the start (though * it doesn't need to be). The ciphertext does not need to be padded (it does for CBC mode). The cipheroffset is * which index to start writing to in ciphertext. Lastly, the textLength is how many byte items to encrypt from * plaintext; this can be less than plaintext's length. *
* This uses CBC mode, so it takes two IVs instead of how CTR mode takes one nonce. If the IVs aren't sufficiently * random, this produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, though this isn't * clear yet. CTR mode doesn't need its ciphertext to have padding. CBC mode requires textLength to be a multiple of * 16 when decrypting (usually guaranteed by padding). * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param iv1 a long that was used as iv1 to encrypt this specific data * @param iv2 a long that was used as iv2 to encrypt this specific data * @param plaintext the byte array to write to * @param plainOffset which index to start writing to in plaintext * @param ciphertext the byte array to read coded data from * @param cipherOffset which index to start reading from in ciphertext * @param textLength how many byte items to read from ciphertext * @return plaintext, after modifications */ public static byte[] decryptCBC(long k1, long k2, long k3, long k4, long iv1, long iv2, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset, int textLength) { if((textLength & 15) != 0) throw new UnsupportedOperationException("textLength must be a multiple of 16"); int blocks = textLength + 15 >>> 4, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long last0 = iv2, last1 = iv1; do { decrypt(kx, plaintext, plainOffset, ciphertext, cipherOffset); xorIntoBytes(plaintext, plainOffset, last0); xorIntoBytes(plaintext, plainOffset + 8, last1); last0 = fromBytes(ciphertext, cipherOffset); last1 = fromBytes(ciphertext, cipherOffset + 8); plainOffset += 16; cipherOffset += 16; i++; } while (i < blocks); return plaintext; } /** * One of the main ways here to encrypt a "plaintext" long array and get back a coded "ciphertext" long array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being encrypted. The plaintext is the * long array to encrypt; it will not be modified here. The plainOffset is which index in plaintext to start reading * from. The ciphertext is the long array that will be written to, and should usually be empty at the start (though * it doesn't need to be). The ciphertext does not need to be padded (it does for CBC mode). The cipheroffset is * which index to start writing to in ciphertext. Lastly, the textLength is how many long items to encrypt from * plaintext; this can be less than plaintext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that must never be reused as nonce again under the same key; needed to decrypt * @param plaintext the long array to encrypt; will not be modified * @param plainOffset which index to start reading from plaintext * @param ciphertext the long array to write encrypted data to; will be modified * @param cipherOffset which index to start writing to in ciphertext * @param textLength how many long items to read and encrypt from plaintext * @return ciphertext, after modifications */ public static long[] encryptCTR(long k1, long k2, long k3, long k4, long nonce, long[] plaintext, int plainOffset, long[] ciphertext, int cipherOffset, int textLength) { int blocks = textLength + 1 >>> 1, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long counter = 0L; do { encrypt(kx, nonce, counter++, null, 0, ciphertext, cipherOffset); ciphertext[cipherOffset] ^= plaintext[plainOffset] ; if(plainOffset + 1 < plaintext.length && cipherOffset + 1 < ciphertext.length) ciphertext[cipherOffset+1] ^= plaintext[plainOffset+1]; plainOffset+=2; cipherOffset+=2; i++; } while(i < blocks); return ciphertext; } /** * One of the main ways here to encrypt a "plaintext" byte array and get back a coded "ciphertext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being encrypted. The plaintext is the * byte array to encrypt; it will not be modified here. The plainOffset is which index in plaintext to start reading * from. The ciphertext is the byte array that will be written to, and should usually be empty at the start (though * it doesn't need to be). The ciphertext does not need to be padded (it does for CBC mode). The cipheroffset is * which index to start writing to in ciphertext. Lastly, the textLength is how many byte items to encrypt from * plaintext; this can be less than plaintext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that must never be reused as nonce again under the same key; needed to decrypt * @param plaintext the byte array to encrypt; will not be modified * @param plainOffset which index to start reading from plaintext * @param ciphertext the byte array to write encrypted data to; will be modified * @param cipherOffset which index to start writing to in ciphertext * @param textLength how many byte items to read and encrypt from plaintext * @return ciphertext, after modifications */ public static byte[] encryptCTR(long k1, long k2, long k3, long k4, long nonce, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset, int textLength) { int blocks = textLength + 15 >>> 4, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long counter = 0L; do { encrypt(kx, nonce, counter++, null, 0, ciphertext, cipherOffset); for (int x = 0, n = Math.min(16, Math.min(ciphertext.length - cipherOffset, plaintext.length - plainOffset)); x < n; x++, cipherOffset++, plainOffset++) { ciphertext[cipherOffset] ^= plaintext[plainOffset]; } i++; } while(i < blocks); return ciphertext; } /** * One of the main ways here to encrypt a "plaintext" byte array and get back a coded "ciphertext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being encrypted. The plaintext is the * byte array to encrypt; it will not be modified here. The plainOffset is which index in plaintext to start reading * from. The ciphertext is the byte array that will be written to, and should usually be empty at the start (though * it doesn't need to be). The ciphertext does not need to be padded (it does for CBC mode). The cipheroffset is * which index to start writing to in ciphertext. Lastly, the textLength is how many byte items to encrypt from * plaintext; this can be less than plaintext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that must never be reused as nonce again under the same key; needed to decrypt * @param nonce2 an int that must never be reused as nonce2 again under the same key; needed to decrypt * @param plaintext the byte array to encrypt; will not be modified * @param plainOffset which index to start reading from plaintext * @param ciphertext the byte array to write encrypted data to; will be modified * @param cipherOffset which index to start writing to in ciphertext * @param textLength how many byte items to read and encrypt from plaintext * @return ciphertext, after modifications */ public static byte[] encryptCTR(long k1, long k2, long k3, long k4, long nonce, int nonce2, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset, int textLength) { int blocks = textLength + 15 >>> 4, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long counter = 0L; do { encrypt(kx, nonce, nonce2 ^ (counter += 0x100000000L), null, 0, ciphertext, cipherOffset); for (int x = 0, n = Math.min(16, Math.min(ciphertext.length - cipherOffset, plaintext.length - plainOffset)); x < n; x++, cipherOffset++, plainOffset++) { ciphertext[cipherOffset] ^= plaintext[plainOffset]; } i++; } while(i < blocks); return ciphertext; } /** * One of the main ways here to decrypt a coded "ciphertext" long array and get back a "plaintext" long array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being decrypted. The plaintext is the * long array that will receive the decrypted final result. The plainOffset is which index in plaintext to start * writing to. The ciphertext is the long array that contains coded data, and should have been encrypted by * {@link #encryptCTR(long, long, long, long, long, long[], int, long[], int, int)}. The ciphertext does not need to * be padded (it does for CBC mode). The cipheroffset is which index to start reading from in ciphertext. Lastly, * the textLength is how many long items to decrypt from ciphertext; this can be less than ciphertext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. CBC mode requires textLength * to be a multiple of 2 (16 bytes) when decrypting (usually guaranteed by padding). * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that was used as nonce to encrypt this specific data * @param plaintext the long array to receive decrypted data; will be modified * @param plainOffset which index to start writing to in plaintext * @param ciphertext the long array to read encrypted data from; will not be modified * @param cipherOffset which index to start reading from in ciphertext * @param textLength how many long items to read and decrypt from ciphertext * @return plaintext, after modifications */ public static long[] decryptCTR(long k1, long k2, long k3, long k4, long nonce, long[] plaintext, int plainOffset, long[] ciphertext, int cipherOffset, int textLength) { return encryptCTR(k1, k2, k3, k4, nonce, ciphertext, cipherOffset, plaintext, plainOffset, textLength); } /** * One of the main ways here to decrypt a coded "ciphertext" byte array and get back a "plaintext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being decrypted. The plaintext is the * byte array that will receive the decrypted final result. The plainOffset is which index in plaintext to start * writing to. The ciphertext is the byte array that contains coded data, and should have been encrypted by * {@link #encryptCTR(long, long, long, long, long, byte[], int, byte[], int, int)}. The ciphertext does not need to * be padded (it does for CBC mode). The cipheroffset is which index to start reading from in ciphertext. Lastly, * the textLength is how many byte items to decrypt from ciphertext; this can be less than ciphertext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. CBC mode requires textLength * to be a multiple of 16 when decrypting (usually guaranteed by padding). * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that was used as nonce to encrypt this specific data * @param plaintext the byte array to receive decrypted data; will be modified * @param plainOffset which index to start writing to in plaintext * @param ciphertext the byte array to read encrypted data from; will not be modified * @param cipherOffset which index to start reading from in ciphertext * @param textLength how many byte items to read and decrypt from ciphertext * @return plaintext, after modifications */ public static byte[] decryptCTR(long k1, long k2, long k3, long k4, long nonce, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset, int textLength) { return encryptCTR(k1, k2, k3, k4, nonce, ciphertext, cipherOffset, plaintext, plainOffset, textLength); } /** * One of the main ways here to decrypt a coded "ciphertext" byte array and get back a "plaintext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being decrypted. The plaintext is the * byte array that will receive the decrypted final result. The plainOffset is which index in plaintext to start * writing to. The ciphertext is the byte array that contains coded data, and should have been encrypted by * {@link #encryptCTR(long, long, long, long, long, byte[], int, byte[], int, int)}. The ciphertext does not need to * be padded (it does for CBC mode). The cipheroffset is which index to start reading from in ciphertext. Lastly, * the textLength is how many byte items to decrypt from ciphertext; this can be less than ciphertext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. CBC mode requires textLength * to be a multiple of 16 when decrypting (usually guaranteed by padding). * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that was used as nonce to encrypt this specific data * @param nonce2 an int that was used as nonce2 to encrypt this specific data * @param plaintext the byte array to receive decrypted data; will be modified * @param plainOffset which index to start writing to in plaintext * @param ciphertext the byte array to read encrypted data from; will not be modified * @param cipherOffset which index to start reading from in ciphertext * @param textLength how many byte items to read and decrypt from ciphertext * @return plaintext, after modifications */ public static byte[] decryptCTR(long k1, long k2, long k3, long k4, long nonce, int nonce2, byte[] plaintext, int plainOffset, byte[] ciphertext, int cipherOffset, int textLength) { return encryptCTR(k1, k2, k3, k4, nonce, nonce2, ciphertext, cipherOffset, plaintext, plainOffset, textLength); } /** * Encrypts a "plaintext" byte array in-place, making it a coded "ciphertext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being encrypted. The plaintext is the * byte array to encrypt; it will be modified here. The plainOffset is which index in plaintext to start reading * from and writing to. Lastly, the textLength is how many byte items to encrypt from * plaintext; this can be less than plaintext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that must never be reused as nonce again under the same key; needed to decrypt * @param plaintext the byte array to encrypt in-place; will be modified * @param plainOffset which index to start reading from and writing to in plaintext * @param textLength how many byte items to read and encrypt from plaintext */ public static byte[] encryptInPlaceCTR(long k1, long k2, long k3, long k4, long nonce, byte[] plaintext, int plainOffset, int textLength) { int blocks = textLength + 15 >>> 4, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long counter = 0L; do { encryptWithXor(kx, nonce, counter++, plaintext, plainOffset); plainOffset+=16; i++; } while(i < blocks); return plaintext; // now it is encrypted } /** * Decrypts a coded "ciphertext" byte array and changes it in-place to a "plaintext" byte array. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being decrypted. The ciphertext is the * byte array that contains coded data, and should have been encrypted by * {@link #encryptInPlaceCTR(long, long, long, long, long, byte[], int, int)}. The ciphertext will be modified * in-place to become the plaintext. The cipheroffset is which index to start reading from in ciphertext. Lastly, * the textLength is how many byte items to decrypt from ciphertext; this can be less than ciphertext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. CBC mode requires textLength * to be a multiple of 16 when decrypting (usually guaranteed by padding). * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that was used as nonce to encrypt this specific data * @param ciphertext the byte array to read encrypted data from; will be modified in-place * @param cipherOffset which index to start reading from and writing to in ciphertext * @param textLength how many byte items to read and decrypt from ciphertext */ public static byte[] decryptInPlaceCTR(long k1, long k2, long k3, long k4, long nonce, byte[] ciphertext, int cipherOffset, int textLength) { return encryptInPlaceCTR(k1, k2, k3, k4, nonce, ciphertext, cipherOffset, textLength); } /** * Encrypts a "plaintext" ByteBuffer in-place, making it a coded "ciphertext" ByteBuffer. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being encrypted. The plaintext is the * ByteBuffer to encrypt; it will be modified here. The plainOffset is which index in plaintext to start reading * from and writing to. Lastly, the textLength is how many byte items to encrypt from * plaintext; this can be less than plaintext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that must never be reused as nonce again under the same key; needed to decrypt * @param plaintext the ByteBuffer to encrypt in-place; will be modified * @param plainOffset which index to start reading from and writing to in plaintext * @param textLength how many byte items to read and encrypt from plaintext * @return plaintext, after modifications */ public static ByteBuffer encryptInPlaceCTR(long k1, long k2, long k3, long k4, long nonce, ByteBuffer plaintext, int plainOffset, int textLength) { int blocks = textLength + 15 >>> 4, i = 0; long[] kx = expandKey(k1, k2, k3, k4); long counter = 0L; do { encryptWithXor(kx, nonce, counter++, plaintext, plainOffset); plainOffset+=16; i++; } while(i < blocks); return plaintext; } /** * Decrypts a coded "ciphertext" ByteBuffer and changes it in-place to a "plaintext" ByteBuffer. * This takes four {@code long}s as its key (256-bits), and also requires one unique (never used again) long as * the nonce. How you generate keys is up to you, but the keys must be kept secret for encryption to stay secure. * To generate nonce, secrecy isn't as important as uniqueness; calling DistinctRandom.nextLong() even many * times will never return the same long unless nonce are requested for years from one generator, so it is a good * option to produce nonce data. The rest of the arguments are about the data being decrypted. The ciphertext is the * ByteBuffer that contains coded data, and should have been encrypted by * {@link #encryptInPlaceCTR(long, long, long, long, long, ByteBuffer, int, int)}. The ciphertext will be modified * in-place to become the plaintext. The cipheroffset is which index to start reading from in ciphertext. Lastly, * the textLength is how many byte items to decrypt from ciphertext; this can be less than ciphertext's length. *
* This uses CTR mode, so it takes one nonce instead of how CBC mode takes two IVs. If the IVs/nonce aren't * sufficiently random, CBC mode produces higher-quality outputs than CTR mode. CBC mode may be slightly faster, * though this isn't clear yet. CTR mode doesn't need its ciphertext to have padding. CBC mode requires textLength * to be a multiple of 16 when decrypting (usually guaranteed by padding). * @param k1 a secret long; part of the key * @param k2 a secret long; part of the key * @param k3 a secret long; part of the key * @param k4 a secret long; part of the key * @param nonce a long that was used as nonce to encrypt this specific data * @param ciphertext the ByteBuffer to read encrypted data from; will be modified in-place * @param cipherOffset which index to start reading from and writing to in ciphertext * @param textLength how many byte items to read and decrypt from ciphertext * @return ciphertext, after modifications */ public static ByteBuffer decryptInPlaceCTR(long k1, long k2, long k3, long k4, long nonce, ByteBuffer ciphertext, int cipherOffset, int textLength) { return encryptInPlaceCTR(k1, k2, k3, k4, nonce, ciphertext, cipherOffset, textLength); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy