com.github.isaichkindanila.crypt.lib.cipher.StreamCipher Maven / Gradle / Ivy
Show all versions of crypt-lib Show documentation
package com.github.isaichkindanila.crypt.lib.cipher;
/**
* Class representing stream ciphers.
*/
@SuppressWarnings("WeakerAccess")
public abstract class StreamCipher {
/**
* Expected key length in bytes.
*/
public static final int KEY_LENGTH = 32;
/**
* Expected initialization vector length in bytes.
*/
public static final int IV_LENGTH = 16;
private byte[] key;
private byte[] iv;
private byte[] block;
private int index;
/**
* Initializes stream cipher with given key and initialization vector.
*
* @param key 32-byte long key
* @param iv 16-byte long initialization vector
*/
protected abstract void init0(byte[] key, byte[] iv);
/**
* Computes and returns next block of keystream.
*
* Returned array must be not {@code null} and have length greater than 0.
*
* @return next block of keystream
*/
protected abstract byte[] nextBlock();
private byte[] copyOfLength(byte[] source, int length) {
byte[] result = new byte[length];
System.arraycopy(source, 0, result, 0, Math.min(source.length, result.length));
return result;
}
/**
* Used to initialize (or reinitialize) stream cipher with given key and initialization vector.
*
* Key is expected to be 256-bit long (32-byte long),
* and will be truncated or expanded if necessary.
*
* Initialization vector is expected to be 128-bit long (16-byte long),
* and will be truncated or expanded if necessary.
*
* @param key cipher key
* @param iv initialization vector
*/
public final void init(byte[] key, byte[] iv) {
if (key.length != KEY_LENGTH) {
key = copyOfLength(key, KEY_LENGTH);
}
if (iv.length != IV_LENGTH) {
iv = copyOfLength(iv, IV_LENGTH);
}
this.key = key;
this.iv = iv;
this.block = new byte[0];
this.index = 0;
init0(key, iv);
}
/**
* Encrypts/decrypts a byte.
*
* @param b byte to encrypt/decrypt
* @return encrypted/decrypted byte
*/
public final byte apply(byte b) {
if (index == block.length) {
index = 0;
block = nextBlock();
}
return (byte) (b ^ block[index++]);
}
/**
* Encrypts/decrypts byte array.
*
* @param bytes byte array to encrypt/decrypt
*/
public final void apply(byte[] bytes) {
apply(bytes, 0, bytes.length);
}
/**
* Encrypts/decrypts byte array.
*
* @param bytes byte array to encrypt/decrypt
* @param offset the start offset in array
* @param length the number of bytes to encrypt/decrypt
*/
public final void apply(byte[] bytes, int offset, int length) {
for (int i = offset; i < offset + length; i++) {
bytes[i] = apply(bytes[i]);
}
}
/**
* Returns 256-bit long (32-byte long) key of this cipher.
*
* @return key of this cipher
*/
public final byte[] getKey() {
return key;
}
/**
* Return 128-bit long (16-byte long) initialization vector of this cipher.
*
* @return initialization vector of this cipher
*/
public final byte[] getIV() {
return iv;
}
}