Skip to content

Instantly share code, notes, and snippets.

@DrBrad
Last active September 20, 2020 18:35
Show Gist options
  • Save DrBrad/0148f54cb1e5f5b04414c7756b97996a to your computer and use it in GitHub Desktop.
Save DrBrad/0148f54cb1e5f5b04414c7756b97996a to your computer and use it in GitHub Desktop.
Socket Cipher Data Input / Output Stream for AES
import javax.crypto.Cipher;
import javax.crypto.NullCipher;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
public class SRI extends FilterInputStream {
/**
* THIS HAS BEEN TESTED & WORKS WITH
* CTR - WORKS
* GCM - DOESN'T WORK - "Must recreate a new cipher per message"
**/
private Cipher cipher;
private byte[] buf = new byte[8];
private byte[] obuffer = new byte[0];
public SRI(InputStream in){
this(in, new NullCipher());
}
public SRI(InputStream in, Cipher cipher){
super(in);
this.cipher = cipher;
}
/**
* PLEASE NOTE AVAILABLE DOES NOT OUTPUT THE CORRECT AVAILABLE
* IT OUTPUTS DECRYPTED BUFFER LENGTH + ENCRYPTED AVAILABLE THIS
* ENSURES THAT THE AVAILABLE WILL BE > 0 WHILE BYTES COMING IN
**/
public int available()throws IOException {
if(obuffer.length > 0){
return obuffer.length+super.available();
}else{
return super.available();
}
}
public int read()throws IOException {
byte[] buf = new byte[1];
read(buf, 0, 1);
return buf[0];
}
public int read(byte[] buf)throws IOException {
return read(buf, 0, buf.length);
}
/**
* FIRST WE READ AN integer WITH THE ENCRYPTED BYTES LENGTH
* THIS ENSURES THAT WE NEVER OVERLAP DECRYPTION AND CAUSE AN
* ERROR. NEXT WE READ THE MESSAGE TO THE LENGTH AND STORE THE
* REST OF THE MESSAGE IN obuffer AS DECRYPTED BYTES
**/
public int read(byte[] buf, int off, int len)throws IOException {
if(obuffer.length > 0){
if(len < obuffer.length){
System.arraycopy(obuffer, off, buf, 0, len);
obuffer = Arrays.copyOfRange(obuffer, len, obuffer.length);
return len;
}else{
len = obuffer.length;
System.arraycopy(obuffer, off, buf, 0, len);
obuffer = new byte[0];
return len;
}
}else{
obuffer = new byte[getMessageLength()];
int position = 0;
byte[] buffer = new byte[(obuffer.length > 4096) ? 4096 : obuffer.length];
int length;
while(position < obuffer.length){
length = in.read(buffer);
System.arraycopy(buffer, 0, obuffer, position, length);
position += length;
}
try{
obuffer = cipher.doFinal(obuffer);
if(len < obuffer.length){
System.arraycopy(obuffer, off, buf, 0, len);
obuffer = Arrays.copyOfRange(obuffer, len, obuffer.length);
return len;
}else{
len = obuffer.length;
System.arraycopy(obuffer, off, buf, 0, len);
obuffer = new byte[0];
return len;
}
}catch(Exception e){
IOException ioe = new IOException("Cipher can't decrypt message.");
ioe.initCause(e);
throw ioe;
}
}
}
public long skip()throws IOException {
//I haven't implemented this yet...
return 0;
}
public boolean markSupported(){
return false;
}
public void mark(int mark){
}
public void reset()throws IOException {
throw new IOException("reset not supported");
}
//DATA INPUT TIME
public boolean readBoolean()throws Exception {
int b = read();
if(b < 0){
throw new EOFException();
}
return (b != 0);
}
public byte readByte()throws Exception {
int b = read();
if(b < 0){
throw new EOFException();
}
return (byte) b;
}
public short readShort()throws Exception {
readFully(buf, 0, 2);
return (short) ((buf [0] << 8) | (buf [1] & 0xff));
}
public char readChar()throws Exception {
readFully(buf, 0, 2);
return (char) ((buf [0] << 8) | (buf [1] & 0xff));
}
public int readInt()throws Exception {
readFully(buf, 0, 4);
return (((buf[0] & 0xff) << 24) | ((buf[1] & 0xff) << 16) | ((buf[2] & 0xff) << 8) | (buf[3] & 0xff));
}
public long readLong()throws Exception {
readFully(buf, 0, 8);
return (((long)(buf[0] & 0xff) << 56) | ((long)(buf[1] & 0xff) << 48) | ((long)(buf[2] & 0xff) << 40) | ((long)(buf[3] & 0xff) << 32) |
((long)(buf[4] & 0xff) << 24) | ((long)(buf[5] & 0xff) << 16) | ((long)(buf[6] & 0xff) << 8) | ((long)(buf[7] & 0xff)));
}
public float readFloat()throws Exception {
return Float.intBitsToFloat(readInt());
}
public double readDouble()throws Exception {
return Double.longBitsToDouble(readLong());
}
public void readFully(byte[] b, int off, int len)throws Exception {
if(len < 0){
throw new IndexOutOfBoundsException("Negative length: "+len);
}
while(len > 0){
int numread = read(b, off, len);
if(numread < 0){
throw new EOFException();
}
len -= numread;
off += numread;
}
}
private int getMessageLength()throws IOException {
byte[] buffer = new byte[4];
int off = 0, len = 4;
while(len > 0){
int numread = in.read(buffer, off, len);
if(numread < 0){
throw new EOFException();
}
len -= numread;
off += numread;
}
return (((buffer[0] & 0xff) << 24) | ((buffer[1] & 0xff) << 16) | ((buffer[2] & 0xff) << 8) | (buffer[3] & 0xff));
}
}
import javax.crypto.Cipher;
import javax.crypto.NullCipher;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import static java.nio.charset.StandardCharsets.UTF_8;
public class SRO extends FilterOutputStream {
private Cipher cipher;
public SRO(OutputStream out){
this(out, new NullCipher());
}
public SRO(OutputStream out, Cipher cipher){
super(out);
this.cipher = cipher;
}
public void flush()throws IOException {
//System.out.println("FLUSH");
out.flush();
}
public void write(int value)throws IOException {
write(new byte[]{ (byte) value }, 0, 1);
}
public void write(byte[] buf)throws IOException {
write(buf, 0, buf.length);
}
public void write(byte[] buf, int off, int len)throws IOException {
try{
buf = cipher.doFinal(buf, off, len);
setMessageLength(buf.length);
out.write(buf);
}catch(Exception e){
IOException ioex = new IOException(String.valueOf(e));
ioex.initCause(e);
throw ioex;
}
}
//DATA OUTPUT TIME
public void writeBoolean(boolean value)throws Exception {
write(value ? 1 : 0);
}
public void writeByte(int value)throws Exception {
value = value&0xff;
write(value);
}
public void writeShort(int value)throws Exception {
byte[] buf = new byte[]{
(byte) (0xff & (value >> 8)),
(byte) (0xff & value) };
write(buf);
}
public void writeChar(int value)throws Exception {
byte[] buf = new byte[]{
(byte) (0xff & (value >> 8)),
(byte) (0xff & value) };
write(buf);
}
public void writeInt(int value)throws Exception {
byte[] buf = new byte[]{
(byte) (0xff & (value >> 24)),
(byte) (0xff & (value >> 16)),
(byte) (0xff & (value >> 8)),
(byte) (0xff & value) };
write(buf);
}
public void writeLong(long value)throws Exception {
byte[] buf = new byte[]{
(byte) (0xff & (value >> 56)),
(byte) (0xff & (value >> 48)),
(byte) (0xff & (value >> 40)),
(byte) (0xff & (value >> 32)),
(byte) (0xff & (value >> 24)),
(byte) (0xff & (value >> 16)),
(byte) (0xff & (value >> 8)),
(byte) (0xff & value) };
write(buf);
}
public void writeFloat(float value)throws Exception {
writeInt(Float.floatToIntBits(value));
}
public void writeDouble(double value)throws Exception {
writeLong(Double.doubleToLongBits(value));
}
public void writeBytes(String value)throws Exception {
byte[] buf = value.getBytes(UTF_8);
write(buf);
}
public void writeChars(String value)throws Exception {
byte[] buf = value.getBytes(UTF_8);
write(buf);
}
private void setMessageLength(int value)throws Exception {
out.write((byte) (0xff & (value >> 24)));
out.write((byte) (0xff & (value >> 16)));
out.write((byte) (0xff & (value >> 8)));
out.write((byte) (0xff & value));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment