adds a set of files

This commit is contained in:
Timothy Prepscius 2013-07-14 12:38:31 -04:00
parent b0c64f9d08
commit 10028cd6e8
128 changed files with 8039 additions and 0 deletions

10
License.txt Normal file
View File

@ -0,0 +1,10 @@
Portions of this code are release GPL and portions are released BSD.
Anything to do with the web is GPLv3 Affero + keep my name in the code.
Anything to do with the iPhone is BSD + keep my name in the code.
Anything to do with the Android is GPLv3 Affero + keep my name in the code.
License documentation will be placed in each file accordingly.
If you need a different license, please contact me.

View File

@ -0,0 +1,40 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.callback.Callback;
import core.callback.CallbackDefault;
import core.exceptions.CryptoException;
public abstract class Cryptor
{
static final boolean TEST_ENCRYPTION = false;
abstract public byte[] encrypt (byte[] bytes) throws CryptoException;
abstract public byte[] decrypt (byte[] bytes) throws CryptoException;
public Callback encrypt_()
{
return new CallbackDefault() {
@Override
public void onSuccess(Object... arguments) throws Exception {
next(Cryptor.this.encrypt((byte[])arguments[0]));
}
};
}
public Callback decrypt_()
{
return new CallbackDefault() {
@Override
public void onSuccess(Object... arguments) throws Exception {
next(Cryptor.this.decrypt((byte[])arguments[0]));
}
};
}
}

View File

@ -0,0 +1,105 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.callback.Callback;
import core.callback.CallbackDefault;
import core.exceptions.CryptoException;
import core.util.Arrays;
import core.util.LogNull;
import core.util.LogOut;
import core.util.SecureRandom;
public class CryptorAES extends Cryptor
{
static LogNull log = new LogNull(CryptorAES.class);
public static final int AES_KEYSIZE_BYTES = 32;
public static final int AES_IVSIZE_BYTES = 16;
static SecureRandom random = new SecureRandom();
byte[] key;
public CryptorAES (byte[] key)
{
this.key = key;
}
public static final byte[] NullIV = {
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
} ;
public static byte[] newIV()
{
byte[] iv = new byte[AES_IVSIZE_BYTES];
random.nextBytes(iv);
return iv;
}
public static byte[] newKey()
{
byte[] key = new byte[AES_KEYSIZE_BYTES];
random.nextBytes(key);
return key;
}
@Override
public byte[] encrypt(byte[] bytes) throws CryptoException
{
byte[] iv = newIV();
Cryptor cryptor = new CryptorAESIV(key, iv);
return Arrays.concat(iv, cryptor.encrypt(bytes));
}
@Override
public byte[] decrypt(byte[] bytes) throws CryptoException
{
byte[] iv = Arrays.copyOf(bytes, 0, AES_IVSIZE_BYTES);
byte[] data = Arrays.copyOf(bytes, AES_IVSIZE_BYTES, bytes.length - AES_IVSIZE_BYTES);
Cryptor cryptor = new CryptorAESIV(key, iv);
return cryptor.decrypt(data);
}
public Callback decrypt_()
{
return new CallbackDefault() {
public void onSuccess(Object... arguments) throws Exception {
byte[] bytes = (byte[]) arguments[0];
byte[] iv = Arrays.copyOf(bytes, 0, AES_IVSIZE_BYTES);
byte[] data = Arrays.copyOf(bytes, AES_IVSIZE_BYTES, bytes.length - AES_IVSIZE_BYTES);
log.debug("decrypt_", bytes.length, iv.length, data.length);
Cryptor cryptor = new CryptorAESIV(key, iv);
call(cryptor.decrypt_(), data);
}
};
}
public Callback encrypt_()
{
byte[] iv = newIV();
Cryptor cryptor = new CryptorAESIV(key, iv);
return
cryptor.encrypt_()
.addCallback(new CallbackDefault(iv) {
public void onSuccess(Object... arguments) throws Exception {
byte[] iv = V(0);
byte[] data = (byte[]) arguments[0];
log.debug("encrypt_", iv.length, data.length);
next(Arrays.concat(iv, data));
}
});
}
}

View File

@ -0,0 +1,93 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.util.Arrays;
import core.util.SecureRandom;
import org.bc.crypto.BufferedBlockCipher;
import org.bc.crypto.engines.AESEngine;
import org.bc.crypto.modes.CBCBlockCipher;
import org.bc.crypto.paddings.BlockCipherPadding;
import org.bc.crypto.paddings.PKCS7Padding;
import org.bc.crypto.paddings.PaddedBufferedBlockCipher;
import org.bc.crypto.params.KeyParameter;
import org.bc.crypto.params.ParametersWithIV;
import core.exceptions.CryptoException;
public class CryptorAESIV extends Cryptor
{
static SecureRandom random = new SecureRandom();
byte[] key;
byte[] iv;
public CryptorAESIV (byte[] key, byte[] iv)
{
// setup cipher parameters with key and IV
this.key = key;
this.iv = iv;
}
@Override
public byte[] decrypt(byte[] bytes) throws CryptoException
{
try
{
BlockCipherPadding padding = new PKCS7Padding();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()), padding);
ParametersWithIV params = new ParametersWithIV(new KeyParameter(key), iv);
cipher.reset();
cipher.init(false, params);
byte[] out = new byte[cipher.getOutputSize(bytes.length)];
int len = cipher.processBytes(bytes, 0, bytes.length, out, 0);
len += cipher.doFinal(out, len);
if (len == out.length)
return out;
return Arrays.copyOf(out, len);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
@Override
public byte[] encrypt(byte[] bytes) throws CryptoException
{
try
{
BlockCipherPadding padding = new PKCS7Padding();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()), padding);
ParametersWithIV params = new ParametersWithIV(new KeyParameter(key), iv);
cipher.reset();
cipher.init(true, params);
byte[] out = new byte[cipher.getOutputSize(bytes.length)];
int len = cipher.processBytes(bytes, 0, bytes.length, out, 0);
len += cipher.doFinal(out, len);
if (len == out.length)
return out;
return Arrays.copyOf(out, len);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
}

View File

@ -0,0 +1,53 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import core.exceptions.CryptoException;
public class CryptorAESJCE extends Cryptor
{
SecretKeySpec secretKey;
IvParameterSpec iv;
public CryptorAESJCE (SecretKeySpec secretKey, IvParameterSpec iv)
{
this.secretKey = secretKey;
this.iv = iv;
}
public byte[] encrypt(byte[] clearText) throws CryptoException
{
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(clearText);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
public byte[] decrypt(byte[] encrypted) throws CryptoException
{
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
return cipher.doFinal(encrypted);
}
catch (Exception e)
{
throw new CryptoException (e);
}
}
}

View File

@ -0,0 +1,25 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.exceptions.CryptoException;
public class CryptorNone extends Cryptor
{
@Override
public byte[] encrypt(byte[] bytes) throws CryptoException
{
return bytes;
}
@Override
public byte[] decrypt(byte[] bytes) throws CryptoException
{
return bytes;
}
}

View File

@ -0,0 +1,27 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
public abstract class CryptorRSA extends Cryptor
{
byte[] publicKeyBytes, privateKeyBytes;
public byte[] getPublicKey ()
{
return publicKeyBytes;
}
public byte[] getPrivateKey ()
{
return privateKeyBytes;
}
protected void initialize (byte[] publicKeyBytes, byte[] privateKeyBytes)
{
this.privateKeyBytes = privateKeyBytes;
this.publicKeyBytes = publicKeyBytes;
}
}

View File

@ -0,0 +1,216 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import core.util.LogNull;
import core.util.LogOut;
import core.util.Streams;
import core.callback.Callback;
import core.callback.CallbackDefault;
import core.callback.CallbackSync;
import core.callbacks.Memory;
import core.exceptions.CryptoException;
public class CryptorRSAAES extends Cryptor
{
static LogNull log = new LogNull(CryptorRSAAES.class);
CryptorRSA rsa;
public static class Version {
public static final int
R2012 = 0x00,
R201303 = 0x01,
CURRENT = R201303;
};
public final byte INITIAL = 0x00;
public final byte VERSION = 0x01;
public final int MAX_RSA_BLOCK_SIZE = 117;
private final static String M_VERSION = "version";
public CryptorRSAAES(CryptorRSA rsa)
{
this.rsa = rsa;
}
void readVersion (InputStream is, Memory memory) throws Exception
{
int version = is.read()&0xFF;
if (version < 0 || version > Version.CURRENT)
throw new Exception("Unknown version");
memory.put(M_VERSION, version);
log.debug("readVersion", version);
}
void writeVersion (OutputStream os) throws IOException
{
os.write(Version.CURRENT);
log.debug("writeVersion", Version.CURRENT);
}
Callback readEncryptedEmbeddedKey_ (InputStream is, Memory memory)
{
return new CallbackDefault(memory, is) {
public void onSuccess(Object... arguments) throws Exception
{
Memory memory = V(0);
InputStream is = V(1);
int version = (Integer)memory.get(M_VERSION);
switch (version) {
case Version.R2012:
Streams.readInt3(is); // ignore the wrapper
next(Streams.readBoundedArray(is));
break;
case Version.R201303:
next(Streams.readBoundedArray(is));
break;
};
}
};
}
Callback writeEncryptedEmbeddedKey_ (OutputStream os)
{
return new CallbackDefault(os) {
public void onSuccess(Object... arguments) throws Exception
{
OutputStream os = V(0);
byte[] bytes = (byte[]) arguments[0];
Streams.writeBoundedArray(os, bytes);
next(arguments);
}
} ;
}
Callback decryptMainBlock_(InputStream is, Memory memory)
{
return new CallbackDefault (is, memory) {
@Override
public void onSuccess(Object... arguments) throws Exception
{
InputStream is = V(0);
Memory memory = V(1);
byte[] key = (byte[]) arguments[0];
int version = (Integer)memory.get(M_VERSION);
Cryptor cryptor = null;
switch (version)
{
case Version.R2012:
cryptor = new CryptorAESIV(key, CryptorAES.NullIV);
break;
case Version.R201303:
cryptor = new CryptorAES(key);
break;
}
call(cryptor.decrypt_(), Streams.readFullyBytes(is));
}
};
}
Callback encryptMainBlock_ (OutputStream os, Cryptor cryptor, byte[] bytes)
{
return new CallbackDefault (os, cryptor, bytes) {
public void onSuccess(Object... arguments) throws Exception
{
OutputStream os = V(0);
Cryptor cryptor = V(1);
byte[] bytes = V(2);
call(cryptor.encrypt_().addCallback(Streams.writeBytes_(os)), bytes);
}
};
}
public Callback decrypt_()
{
return new CallbackDefault () {
@Override
public void onSuccess(Object... arguments) throws Exception
{
ByteArrayInputStream is = new ByteArrayInputStream((byte[])arguments[0]);
Memory memory = new Memory();
readVersion(is, memory);
call(
readEncryptedEmbeddedKey_(is, memory)
.addCallback(rsa.decrypt_())
.addCallback(decryptMainBlock_(is, memory))
);
}
};
}
public Callback encrypt_ ()
{
return new CallbackDefault () {
@Override
public void onSuccess(Object... arguments) throws Exception
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
writeVersion(os);
byte[] key = CryptorAES.newKey();
CryptorAES aes = new CryptorAES(key);
call(
rsa.encrypt_()
.addCallback(writeEncryptedEmbeddedKey_(os))
.addCallback(encryptMainBlock_(os, aes, (byte[])arguments[0]))
.addCallback(Streams.toByteArray_(os)),
key
);
}
};
}
public byte[] encrypt (byte[] bytes) throws CryptoException
{
try
{
return new CallbackSync<byte[]>(encrypt_()).invoke(bytes).export();
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
public byte[] decrypt (byte[] bytes) throws CryptoException
{
try
{
return new CallbackSync<byte[]>(decrypt_()).invoke(bytes).export();
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
}

View File

@ -0,0 +1,172 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.SecureRandom;
import org.bc.asn1.ASN1InputStream;
import org.bc.asn1.ASN1Integer;
import org.bc.asn1.ASN1ObjectIdentifier;
import org.bc.asn1.ASN1OctetString;
import org.bc.asn1.ASN1Primitive;
import org.bc.asn1.ASN1Sequence;
import org.bc.asn1.DERBitString;
import org.bc.asn1.pkcs.RSAPrivateKey;
import org.bc.asn1.pkcs.RSAPublicKey;
import org.bc.crypto.encodings.PKCS1Encoding;
import org.bc.crypto.engines.RSAEngine;
import org.bc.crypto.params.RSAKeyParameters;
import core.exceptions.CryptoException;
import core.util.Arrays;
public class CryptorRSABC extends CryptorRSA
{
SecureRandom random = new SecureRandom();
public final int MAX_RSA_BLOCK_SIZE = 117;
RSAPublicKey publicKey;
RSAPrivateKey privateKey;
public static final byte[] iv = Arrays.generate(16, 0);
public CryptorRSABC (byte[] publicKey, byte[] privateKey) throws CryptoException
{
initialize(publicKey, privateKey);
try
{
if (privateKey != null)
{
ASN1InputStream asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(privateKey));
ASN1Primitive keyObject = asn1InputStream.readObject();
asn1InputStream.close();
ASN1Sequence keySequence = (ASN1Sequence)keyObject;
ASN1Integer pkcs8Version = (ASN1Integer) keySequence.getObjectAt(0);
ASN1Sequence algorithmSequence = (ASN1Sequence) keySequence.getObjectAt(1);
ASN1ObjectIdentifier algorithmIdentifier = (ASN1ObjectIdentifier) algorithmSequence.getObjectAt(0);
String algorithm = algorithmIdentifier.getId();
if (!algorithm.equals("1.2.840.113549.1.1.1"))
throw new CryptoException("Unknown RSA algorithm");
ASN1OctetString privateKeyOctets = (ASN1OctetString) keySequence.getObjectAt(2);
ASN1InputStream asn1PrivateKeyStream = new ASN1InputStream(privateKeyOctets.getOctetStream());
ASN1Primitive privateKeyObject = asn1PrivateKeyStream.readObject();
asn1PrivateKeyStream.close();
ASN1Sequence privateKeySequence = (ASN1Sequence)privateKeyObject;
int I=0;
ASN1Integer
s = (ASN1Integer)privateKeySequence.getObjectAt(I++),
n = (ASN1Integer)privateKeySequence.getObjectAt(I++),
e = (ASN1Integer)privateKeySequence.getObjectAt(I++),
d = (ASN1Integer)privateKeySequence.getObjectAt(I++),
p = (ASN1Integer)privateKeySequence.getObjectAt(I++),
q = (ASN1Integer)privateKeySequence.getObjectAt(I++),
d1 = (ASN1Integer)privateKeySequence.getObjectAt(I++),
d2 = (ASN1Integer)privateKeySequence.getObjectAt(I++),
c = (ASN1Integer)privateKeySequence.getObjectAt(I++)
;
/*
org.bouncycastle.asn1.pkcs.RSAPrivateKey.RSAPrivateKey(
BigInteger modulus,
BigInteger publicExponent,
BigInteger privateExponent,
BigInteger prime1,
BigInteger prime2,
BigInteger exponent1,
BigInteger exponent2,
BigInteger coefficient
)
*/
this.privateKey =
new RSAPrivateKey(
n.getValue(),
e.getValue(),
d.getValue(),
p.getValue(),
q.getValue(),
d1.getValue(),
d2.getValue(),
c.getValue()
);
}
if (publicKey != null)
{
ASN1InputStream asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(publicKey));
ASN1Primitive keyObject = asn1InputStream.readObject();
asn1InputStream.close();
ASN1Sequence keySequence = (ASN1Sequence)keyObject;
ASN1Sequence algorithmSequence = (ASN1Sequence) keySequence.getObjectAt(0);
ASN1ObjectIdentifier algorithmIdentifier = (ASN1ObjectIdentifier) algorithmSequence.getObjectAt(0);
String algorithm = algorithmIdentifier.getId();
if (!algorithm.equals("1.2.840.113549.1.1.1"))
throw new CryptoException("Unknown RSA algorithm");
DERBitString keyOctets = (DERBitString) keySequence.getObjectAt(1);
ASN1InputStream asn1PublicKeyStream = new ASN1InputStream(new ByteArrayInputStream(keyOctets.getBytes()));
ASN1Primitive publicKeyObject = asn1PublicKeyStream.readObject();
asn1PublicKeyStream.close();
ASN1Sequence publicKeySequence = (ASN1Sequence)publicKeyObject;
int I=0;
ASN1Integer
n = (ASN1Integer)publicKeySequence.getObjectAt(I++),
e = (ASN1Integer)publicKeySequence.getObjectAt(I++);
this.publicKey = new RSAPublicKey(n.getValue(), e.getValue());
}
}
catch (IOException e)
{
throw new CryptoException(e);
}
}
public byte[] encrypt (byte[] block) throws CryptoException
{
try
{
PKCS1Encoding e = new PKCS1Encoding(new RSAEngine());
RSAKeyParameters key = new RSAKeyParameters(false, publicKey.getModulus(), publicKey.getPublicExponent());
e.init(true, key);
return e.processBlock(block, 0, block.length);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
public byte[] decrypt (byte[] block) throws CryptoException
{
try
{
PKCS1Encoding e = new PKCS1Encoding(new RSAEngine());
RSAKeyParameters key = new RSAKeyParameters(false, privateKey.getModulus(), privateKey.getPrivateExponent());
e.init(false, key);
return e.processBlock(block, 0, block.length);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
}

View File

@ -0,0 +1,78 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.bc.crypto.util.PrivateKeyFactory;
import org.bc.crypto.util.PublicKeyFactory;
import core.exceptions.CryptoException;
import core.callback.Callback;
import core.util.Base64;
import core.util.Pair;
public class CryptorRSAFactory
{
public Pair<byte[], byte[]> generate (int bits) throws CryptoException
{
try
{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(bits);
KeyPair keyPair = keyPairGenerator.genKeyPair();
byte[] privateKey = keyPair.getPrivate().getEncoded();
byte[] publicKey = keyPair.getPublic().getEncoded();
return new Pair<byte[], byte[]>(publicKey, privateKey);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
public void generate (int bits, Callback callback)
{
try
{
callback.invoke(generate(bits));
}
catch (CryptoException e)
{
callback.invoke(e);
}
}
public static CryptorRSA fromResources(InputStream publicKey, InputStream privateKey) throws Exception
{
return new CryptorRSAJCE(publicKey, privateKey);
}
public static CryptorRSA fromString(String publicKey, String privateKey) throws Exception
{
return
new CryptorRSAJCE(
publicKey != null ?
KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(
Base64.decode(publicKey))
) :
null,
privateKey != null ?
KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(
Base64.decode(privateKey))
) :
null
);
}
}

View File

@ -0,0 +1,83 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.bc.util.encoders.Base64;
import core.constants.ConstantsEnvironmentKeys;
import core.exceptions.CryptoException;
import core.util.Environment;
public class CryptorRSAFactoryEnvironment
{
public static CryptorRSA createJCE (Environment env) throws CryptoException
{
try
{
PublicKey publicKey = null;
PrivateKey privateKey = null;
String publicKeyString = env.get(ConstantsEnvironmentKeys.PUBLIC_ENCRYPTION_KEY);
if (publicKeyString != null)
{
publicKey =
KeyFactory.getInstance("RSA").generatePublic(
new X509EncodedKeySpec((byte[])Base64.decode(publicKeyString))
);
}
String privateKeyString = env.get(ConstantsEnvironmentKeys.PRIVATE_DECRYPTION_KEY);
if (privateKeyString != null)
{
privateKey =
KeyFactory.getInstance("RSA").generatePrivate(
new PKCS8EncodedKeySpec((byte[])Base64.decode(privateKeyString))
);
}
return new CryptorRSAJCE (publicKey, privateKey);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
/*
public static CryptorRSA createBC (Environment env) throws CryptoException
{
try
{
Base64 base64 = new Base64();
String publicKeyString = env.get(ConstantsEnvironmentKeys.PUBLIC_ENCRYPTION_KEY);
byte[] publicKeyBytes = null;
if (publicKeyString != null)
publicKeyBytes = (byte[])base64.decode(publicKeyString);
String privateKeyString = env.get(ConstantsEnvironmentKeys.PRIVATE_DECRYPTION_KEY);
byte[] privateKeyBytes = null;
if (privateKeyString != null)
privateKeyBytes = base64.decode(privateKeyString);
return new CryptorRSABC (publicKeyBytes, privateKeyBytes);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
*/
public static CryptorRSA create (Environment env) throws CryptoException
{
return createJCE(env);
}
}

View File

@ -0,0 +1,91 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import core.exceptions.CryptoException;
public class CryptorRSAJCE extends CryptorRSA
{
SecureRandom random = new SecureRandom();
public final int MAX_RSA_BLOCK_SIZE = 117;
PublicKey publicKey;
PrivateKey privateKey;
public CryptorRSAJCE (InputStream keyStore, InputStream trustStore) throws Exception
{
if (keyStore != null)
{
KeyStore kks = KeyStore.getInstance("JKS");
kks.load(keyStore, "password".toCharArray());
privateKey = (PrivateKey)kks.getKey(kks.aliases().nextElement(), "password".toCharArray());
if (privateKey == null)
throw new CryptoException(new Exception("RSA Private Key not found in KeyStore."));
}
if (trustStore != null)
{
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(trustStore, "password".toCharArray());
publicKey = tks.getCertificate(tks.aliases().nextElement()).getPublicKey();
if (publicKey == null)
throw new CryptoException(new Exception("RSA Public Key not found in KeyStore."));
}
initialize(
publicKey!=null ? publicKey.getEncoded() : null,
privateKey!=null ? privateKey.getEncoded() : null
);
}
public CryptorRSAJCE (PublicKey publicKey, PrivateKey privateKey)
{
this.publicKey = publicKey;
this.privateKey = privateKey;
initialize(
publicKey!=null ? publicKey.getEncoded() : null,
privateKey!=null ? privateKey.getEncoded() : null
);
}
public byte[] encrypt (byte[] block) throws CryptoException
{
try
{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(block, 0, block.length);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
public byte[] decrypt (byte[] block) throws CryptoException
{
try
{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(block, 0, block.length);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
}

View File

@ -0,0 +1,16 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
public class CryptorSeed
{
public byte[] seed;
public CryptorSeed(byte[] seed)
{
this.seed = seed;
}
}

View File

@ -0,0 +1,26 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import org.bc.crypto.digests.MD5Digest;
public class HashMd5
{
public HashMd5 ()
{
}
public byte[] hash (byte[] bytes)
{
MD5Digest digest = new MD5Digest();
byte[] out = new byte[digest.getDigestSize()];
digest.update(bytes, 0, bytes.length);
digest.doFinal(out, 0);
return out;
}
}

View File

@ -0,0 +1,26 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import org.bc.crypto.digests.SHA256Digest;
public class HashSha256
{
public HashSha256 ()
{
}
public byte[] hash (byte[] bytes)
{
SHA256Digest digest = new SHA256Digest();
byte[] out = new byte[digest.getDigestSize()];
digest.update(bytes, 0, bytes.length);
digest.doFinal(out, 0);
return out;
}
}

View File

@ -0,0 +1,32 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import org.bc.crypto.digests.SHA1Digest;
import org.bc.crypto.macs.HMac;
import org.bc.crypto.params.KeyParameter;
public class HmacSha1
{
HMac mac;
byte[] key;
public HmacSha1(byte[] key)
{
mac = new HMac(new SHA1Digest());
mac.init(new KeyParameter(key));
}
public byte[] mac(byte[] bytes)
{
mac.update(bytes, 0, bytes.length);
byte[] out = new byte[mac.getMacSize()];
mac.doFinal(out, 0);
return out;
}
}

View File

@ -0,0 +1,75 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.callback.Callback;
import core.callback.CallbackChain;
import core.callback.CallbackDefault;
import core.exceptions.CryptoException;
public class KeyPairFromPassword
{
String password;
public PBE[] pbe = { new PBE(), new PBE() };
static final int CRYPTOR = 0, VERIFIER = 1;
public KeyPairFromPassword (String password)
{
this.password = password;
}
public Callback generate_()
{
CallbackChain chain = new CallbackChain();
return chain
.addCallback(
pbe[CRYPTOR].generate_(
password,
PBE.DEFAULT_SALT[CRYPTOR],
PBE.DEFAULT_ITERATIONS,
PBE.DEFAULT_KEYLENGTH
)
)
.addCallback(
pbe[VERIFIER].generate_(
password,
PBE.DEFAULT_SALT[VERIFIER],
PBE.DEFAULT_ITERATIONS,
PBE.DEFAULT_KEYLENGTH
)
)
.addCallback(
new CallbackDefault() {
public void onSuccess(Object... arguments) throws Exception {
next(KeyPairFromPassword.this);
}
}
);
}
public void generate() throws CryptoException
{
for (int i=0; i<2; ++i)
pbe[i].generate(
password,
PBE.DEFAULT_SALT[i],
PBE.DEFAULT_ITERATIONS,
PBE.DEFAULT_KEYLENGTH
);
}
public byte[] getVerifier ()
{
return pbe[VERIFIER].key;
}
public PBE getCryptor ()
{
return pbe[CRYPTOR];
}
}

View File

@ -0,0 +1,41 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.callback.Callback;
import core.exceptions.CryptoException;
public class KeyPairFromPasswordCryptor extends Cryptor
{
KeyPairFromPassword keyPair;
public KeyPairFromPasswordCryptor (KeyPairFromPassword keyPair)
{
this.keyPair = keyPair;
}
public byte[] encrypt (byte[] clearBlock) throws CryptoException
{
return keyPair.getCryptor().encrypt(clearBlock);
}
public byte[] decrypt (byte[] encryptedBlock) throws CryptoException
{
return keyPair.getCryptor().decrypt(encryptedBlock);
}
@Override
public Callback encrypt_()
{
return keyPair.getCryptor().encrypt_();
}
@Override
public Callback decrypt_()
{
return keyPair.getCryptor().decrypt_();
}
}

View File

@ -0,0 +1,105 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import org.bc.crypto.PBEParametersGenerator;
import org.bc.crypto.digests.SHA256Digest;
import org.bc.crypto.generators.PKCS5S2ParametersGenerator;
import org.bc.crypto.params.KeyParameter;
import core.callback.Callback;
import core.callback.CallbackDefault;
import core.crypt.Cryptor;
import core.crypt.CryptorAES;
import core.exceptions.CryptoException;
import core.util.Arrays;
import core.util.Base64;
import core.util.LogNull;
import core.util.LogOut;
/**
* http://stackoverflow.com/questions/992019/java-256-bit-aes-password-based-encryption
*/
public class PBE extends Cryptor
{
LogNull log = new LogNull(PBE.class);
public byte[] key = null;
Cryptor cryptorAES;
public static final int DEFAULT_ITERATIONS = 131072;
public static final int SHORT_ITERATIONS = 32768;
public static final int DEFAULT_KEYLENGTH = 256;
/**
* bytes used to salt the key (set before making an instance)
*/
public static final byte[] DEFAULT_SALT_0 = {
(byte)0xc8, (byte)0x73, (byte)0x41, (byte)0x8c,
(byte)0x7e, (byte)0xd8, (byte)0xee, (byte)0x89
};
/**
* bytes used to salt the key (set before making an instance)
*/
public static final byte[] DEFAULT_SALT_1 = {
(byte)0x12, (byte)0x53, (byte)0x14, (byte)0xbb,
(byte)0x7e, (byte)0x97, (byte)0xce, (byte)0x55
};
/**
* bytes used to salt the key (set before making an instance)
*/
public static final byte[] DEFAULT_SALT_2 = {
(byte)0x0a, (byte)0x48, (byte)0x33, (byte)0xfe,
(byte)0xa7, (byte)0xc2, (byte)0x2c, (byte)0x71
};
public static final byte[][] DEFAULT_SALT = { DEFAULT_SALT_0, DEFAULT_SALT_1, DEFAULT_SALT_2 };
public PBE ()
{
}
public PBE (String password, byte[] salt, int iterationCount, int keyLength) throws CryptoException
{
generate(password,salt, iterationCount, keyLength);
}
public void generate (String password, byte[] salt, int iterationCount, int keyLength)
throws CryptoException
{
key = PBEPlatform.generate(password, salt, iterationCount, keyLength);
cryptorAES = new CryptorAES (key);
log.debug("computed", new String(Base64.encode(key)), " using ", new String(password),"salt",new String(Base64.encode(salt)), iterationCount, keyLength);
}
public Callback generate_ (String password, byte[] salt, int iterationCount, int keyLength)
{
return
new CallbackDefault(password, salt, iterationCount, keyLength) {
public void onSuccess(Object... arguments) throws Exception {
String password = V(0);
byte[] salt = V(1);
int iterationCount = (Integer)V(2);
int keyLength = (Integer)V(3);
generate(password, salt, iterationCount, keyLength);
}
};
}
public byte[] encrypt(byte[] clearText) throws CryptoException
{
return cryptorAES.encrypt(clearText);
}
public byte[] decrypt(byte[] encrypted) throws CryptoException
{
return cryptorAES.decrypt(encrypted);
}
}

View File

@ -0,0 +1,16 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.exceptions.CryptoException;
public class PBEPlatform
{
static byte[] generate (String password, byte[] salt, int iterationCount, int keyLength) throws CryptoException
{
return PBEPlatformBC.generate(password, salt, iterationCount, keyLength);
}
}

View File

@ -0,0 +1,29 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import org.bc.crypto.PBEParametersGenerator;
import org.bc.crypto.digests.SHA256Digest;
import org.bc.crypto.generators.PKCS5S2ParametersGenerator;
import org.bc.crypto.params.KeyParameter;
import core.exceptions.CryptoException;
public class PBEPlatformBC
{
public static byte[] generate (String password, byte[] salt, int iterationCount, int keyLength)
throws CryptoException
{
PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
generator.init(
PBEParametersGenerator.PKCS5PasswordToBytes(password.toCharArray()),
salt,
iterationCount
);
return ((KeyParameter)generator.generateDerivedParameters(keyLength)).getKey();
}
}

View File

@ -0,0 +1,13 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import core.exceptions.CryptoException;
public class PBEPlatformNative
{
public native static byte[] generate (String password, byte[] salt, int iterationCount, int keyLength);
}

View File

@ -0,0 +1,30 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.crypt;
import java.io.Serializable;
public class PasswordValidator implements Serializable
{
private static final long serialVersionUID = 1L;
public String user;
public String password;
byte[] payload;
public PasswordValidator (String user, String password, byte[] payload)
{
this.user = user;
this.password = password;
this.payload = payload;
}
public PasswordValidator (String user, String password)
{
this(user, password, null);
}
}

View File

@ -0,0 +1,19 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.exceptions;
public class CryptoException extends Exception
{
public CryptoException (Exception e)
{
super(e);
}
public CryptoException(String s)
{
super(s);
}
}

View File

@ -0,0 +1,23 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.exceptions;
import org.timepedia.exporter.client.Export;
import org.timepedia.exporter.client.Exportable;
@Export
public class InternalException extends PublicMessageException implements Exportable
{
public InternalException (Exception e)
{
super("An internal error has occurred with " + e.getClass().getName(), e);
}
public InternalException (String with, Exception e)
{
super("An internal error has occurred with " + with, e);
}
}

View File

@ -0,0 +1,32 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.exceptions;
import org.timepedia.exporter.client.Export;
import org.timepedia.exporter.client.Exportable;
@Export
public class PublicMessageException extends RuntimeException implements Exportable
{
public String message;
public PublicMessageException (String message)
{
this.message = message;
}
public PublicMessageException (String message, Exception e)
{
super(e);
this.message = message;
}
@Override
public String getMessage ()
{
return message;
}
}

View File

@ -0,0 +1,16 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.exceptions;
import java.io.IOException;
public class UserExistsException extends PublicMessageException
{
public UserExistsException ()
{
super("User already exists");
}
}

View File

@ -0,0 +1,98 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
public abstract class IoChain
{
protected boolean finished = false;
protected IoChain sender, receiver;
public IoChain (IoChain sender)
{
if (sender != null)
setSender(sender);
}
public void setSender (IoChain sender)
{
this.sender = sender;
sender.setReceiver (this);
}
public void setReceiver (IoChain receiver)
{
this.receiver = receiver;
}
public void send (byte[] packet) throws Exception
{
this.sender.send(packet);
}
protected void onReceive (byte[] object) throws Exception
{
receiver.onReceive(object);
}
public void receive(byte[] object)
{
try
{
onReceive(object);
}
catch (Exception e)
{
onException(e);
}
}
public void onException (Exception e)
{
if (receiver != null)
receiver.onException(e);
}
public IoChain getFinalSender ()
{
if (sender != null)
return sender.getFinalSender();
return this;
}
public void open () throws Exception
{
if (receiver != null)
receiver.open();
}
protected void close () throws Exception
{
if (sender != null)
sender.close();
}
public void stop () throws Exception
{
if (receiver != null)
receiver.stop();
else
close();
}
public void run () throws Exception
{
if (sender != null)
sender.run();
else
open();
}
public boolean isFinished ()
{
return finished;
}
}

View File

@ -0,0 +1,83 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
import java.util.ArrayList;
import java.util.List;
import core.util.LogNull;
import core.util.LogOut;
public class IoChainAccumulator extends IoChain
{
LogNull log = new LogNull(IoChainAccumulator.class);
List<byte[]> out;
boolean opened, closed;
Exception exception;
public IoChainAccumulator()
{
super(null);
out = new ArrayList<byte[]>();
}
@Override
public void send(byte[] packet) throws Exception
{
log.debug("accumulating packet");
out.add(packet);
}
@Override
protected void onReceive(byte[] object) throws Exception
{
super.onReceive(object);
}
@Override
public void open () throws Exception
{
opened = true;
super.open();
}
@Override
protected void close () throws Exception
{
closed = true;
super.close();
}
public void onException(Exception e)
{
this.exception = e;
super.onException(e);
}
public List<byte[]> getAndClearPackets()
{
List<byte[]> result = out;
out = new ArrayList<byte[]>();
return result;
}
public Exception getAndClearException ()
{
Exception e = this.exception;
this.exception = null;
return e;
}
public boolean isOpened ()
{
return opened;
}
public boolean isClosed ()
{
return closed;
}
}

View File

@ -0,0 +1,41 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
import java.io.IOException;
import core.util.Base64;
import core.util.LogNull;
import core.util.LogOut;
public class IoChainBase64 extends IoChain
{
static LogNull log = new LogNull(IoChainBase64.class);
public IoChainBase64(IoChain sender)
{
super(sender);
}
@Override
public void send(byte[] packet) throws Exception
{
byte[] encoded = Base64.encodeBytes(packet);
// log.debug("send base64 check:", Strings.toString(Base64.decode(encoded)));
super.send(encoded);
}
@Override
protected void onReceive (byte[] packet) throws Exception
{
byte[] decoded = Base64.decodeBytes(packet);
// log.debug("onReceive:",new String(packet));
super.onReceive(decoded);
}
}

View File

@ -0,0 +1,10 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
public class IoChainFinishedException extends Exception {
}

View File

@ -0,0 +1,65 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import core.util.LogNull;
import core.util.Strings;
public class IoChainNewLinePackets extends IoChain
{
LogNull log = new LogNull(IoChainNewLinePackets.class);
List<byte[]> packets = new ArrayList<byte[]>();
ByteArrayOutputStream unfinished = new ByteArrayOutputStream();
public IoChainNewLinePackets(IoChain sender)
{
super(sender);
}
@Override
protected void onReceive(byte[] bytes) throws Exception
{
for (byte b: bytes)
{
if (b == '\n' || b == '\r')
{
log.debug("found newline");
if (unfinished.size()>0)
{
packets.add(unfinished.toByteArray());
unfinished = new ByteArrayOutputStream();
}
}
else
{
unfinished.write(b);
}
}
while (!packets.isEmpty())
{
log.debug("recieving packet");
byte[] packet = packets.get(0);
packets.remove(0);
super.onReceive(packet);
}
}
@Override
public void send (byte[] bytes) throws Exception
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(bytes);
bos.write(Strings.toBytes("\n"));
super.send(bos.toByteArray());
}
}

View File

@ -0,0 +1,32 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class IoChainSSLSocket extends IoChainSocket
{
public IoChainSSLSocket(SSLContext context, String host, int port) throws Exception
{
useSocket(createSSLSocket(context, host, port));
}
public Socket createSSLSocket (SSLContext context, String host, int port) throws UnknownHostException, IOException
{
SSLSocketFactory sslsocketfactory = context.getSocketFactory();
SSLSocket socket = (SSLSocket) sslsocketfactory.createSocket(host, port);
socket.setUseClientMode(true);
return socket;
}
}

View File

@ -0,0 +1,87 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import core.util.CircularByteBuffer;
public class IoChainSizedPackets extends IoChain
{
DataInputStream in;
CircularByteBuffer internalIn;
Integer nextPacket;
public IoChainSizedPackets (IoChain sender) throws IOException
{
super(sender);
internalIn = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
this.in = new DataInputStream(internalIn.getInputStream());
}
public boolean ready () throws IOException
{
if (nextPacket == null)
{
if (in.available() >= Integer.SIZE/8)
nextPacket = in.readInt();
}
if (nextPacket != null)
return in.available() >= nextPacket;
return false;
}
@Override
protected void onReceive(byte[] bytes) throws Exception
{
internalIn.getOutputStream().write(bytes);
while (ready())
read();
}
@Override
public void send(byte[] bytes) throws Exception
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int size = bytes.length;
dos.writeInt(size);
dos.write(bytes);
dos.flush();
super.send(bos.toByteArray());
}
public void read () throws Exception
{
if (!ready())
throw new IOException();
byte[] buf = new byte[nextPacket];
if (in.read(buf, 0, nextPacket) != nextPacket)
throw new IOException ();
nextPacket = null;
super.onReceive(buf);
}
public boolean eof () throws IOException
{
return false;
}
}

View File

@ -0,0 +1,111 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import core.util.CircularByteBuffer;
public class IoChainSocket extends IoChain implements Runnable
{
String host;
int port;
Socket socket;
InputStream in;
OutputStream out;
protected IoChainSocket() throws Exception
{
super(null);
}
protected void useSocket (Socket socket) throws Exception
{
this.socket = socket;
in = socket.getInputStream();
out = socket.getOutputStream();
}
public IoChainSocket(String host, int port)
{
super(null);
this.host = host;
this.port = port;
}
@Override
public void open () throws Exception
{
if (socket == null)
useSocket(new Socket(host, port));
super.open();
}
@Override
protected void close () throws Exception
{
if (socket != null)
{
socket.close();
socket = null;
}
}
public boolean pumpBlock () throws Exception
{
CircularByteBuffer buffer = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
boolean first = true;
while (socket!= null && (first || in.available()>0))
{
first = false;
int c = in.read();
if (c == -1)
throw new IoChainFinishedException();
buffer.getOutputStream().write(c);
}
if (buffer.getAvailable() > 0)
{
byte[] b = new byte[buffer.getAvailable()];
buffer.getInputStream().read(b);
receive(b);
}
return socket != null;
}
@Override
public void send(byte[] bytes) throws IOException
{
out.write(bytes);
}
@Override
public void run ()
{
try
{
open();
while (pumpBlock()) ;
}
catch (Exception e)
{
onException(e);
}
}
}

View File

@ -0,0 +1,29 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
public class IoChainThread extends Thread
{
IoChain session;
public IoChainThread (IoChain session)
{
this.session = session;
}
@Override
public void run()
{
try
{
((IoChain)session).run();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,47 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.io;
import java.io.InputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
public class SSLContextGenerator
{
static public SSLContext getSslContext(InputStream clientKeyStore, InputStream serverKeyStore)
{
SSLContext sslContext = null;
try
{
KeyStore cks = KeyStore.getInstance("JKS");
cks.load(clientKeyStore, "password".toCharArray());
KeyStore sks = KeyStore.getInstance("JKS");
sks.load(serverKeyStore, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(cks, "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
tmf.init(sks);
// this might need to be SSL not TLS
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslContext;
}
catch (Exception ex)
{
ex.printStackTrace();
}
return sslContext;
}
}

View File

@ -0,0 +1,146 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.server.captcha;
import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;
import core.server.captcha.sql.Catalog;
import core.util.Passwords;
public class Captcha
{
Random random = new SecureRandom();
Catalog catalog = new Catalog();
public static final String
SignUp = "SignUp",
CreateBucket = "CreateBucket";
public void prune () throws SQLException, IOException
{
Connection connection = openConnection();
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.PRUNE_TOKENS));
log(statement);
statement.executeUpdate();
}
finally
{
closeConnection(connection);
}
}
protected void insertCaptchToken (String token, String use) throws SQLException, IOException
{
Connection connection = openConnection();
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.ADD_TOKEN));
statement.setString(1, token + "_" + use);
log(statement);
statement.executeUpdate();
}
finally
{
closeConnection(connection);
}
}
public String captchaSucceeded () throws SQLException, IOException
{
String token = BigInteger.valueOf(Math.abs(random.nextLong())).toString(32);
insertCaptchToken (token, SignUp);
insertCaptchToken (token, CreateBucket);
return token;
}
public void useToken (String token, String use) throws SQLException, IOException
{
prune();
Connection connection = openConnection();
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.CHECK_TOKEN));
statement.setString(1, token + "_" + use);
log(statement);
ResultSet rs = statement.executeQuery();
if (!rs.next())
throw new IOException ("Null captcha");
rs.close();
statement = connection.prepareStatement (catalog.getSingle(Catalog.USE_TOKEN));
statement.setString(1, token + "_" + use);
log(statement);
statement.executeUpdate();
}
finally
{
closeConnection(connection);
}
}
public void ensureTables() throws SQLException, IOException
{
Connection connection = openConnection();
try
{
for (String sql : catalog.getMulti(Catalog.CREATE_TABLES))
{
PreparedStatement statement = connection.prepareStatement (sql);
log(statement);
statement.executeUpdate();
}
}
finally
{
closeConnection(connection);
}
}
public Connection openConnection () throws SQLException, IOException
{
return DriverManager.getConnection(Catalog.CONNECTION_STRING, Catalog.USER, Passwords.getPasswordFor(Catalog.USER));
}
public void closeConnection (Connection connection)
{
try
{
if (connection != null)
connection.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void log (Statement sql)
{
System.out.println (sql);
}
}

View File

@ -0,0 +1,22 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.server.captcha.sql;
import core.constants.ConstantsServer;
import core.util.SqlCatalog;
public final class Catalog extends SqlCatalog
{
static public final String CONNECTION_STRING = ConstantsServer.DBCONNECTION_PREFIX + "captcha";
public static final String USER = "captcha";
static public final String CREATE_TABLES = "create_tables";
static public final String USE_TOKEN = "use_token";
static public final String CHECK_TOKEN = "check_token";
static public final String ADD_TOKEN = "add_token";
static public final String PRUNE_TOKENS = "prune_tokens";
}

View File

@ -0,0 +1 @@
INSERT INTO captcha (token) values (?)

View File

@ -0,0 +1 @@
SELECT true FROM captcha WHERE token=?

View File

@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS captcha (
token VARCHAR(255),
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (token)
)

View File

@ -0,0 +1 @@
DELETE FROM captcha WHERE mark < DATE_SUB(now(), INTERVAL 2 HOUR);

View File

@ -0,0 +1 @@
DELETE FROM captcha WHERE token=?

View File

@ -0,0 +1,479 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.server.srp.db;
import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Date;
import core.exceptions.CryptoException;
import core.exceptions.PublicMessageException;
import core.exceptions.UserExistsException;
import core.server.srp.db.sql.Catalog;
import core.util.LogOut;
import core.util.Pair;
import core.util.Passwords;
import core.util.Strings;
import core.util.Triple;
import core.util.Base64;
public abstract class UserDb
{
static LogOut log = new LogOut(UserDb.class);
SecureRandom random = new SecureRandom();
Catalog catalog;
protected UserDb (Catalog catalog)
{
this.catalog = catalog;
}
public void testCreateUser (String version, String userName) throws Exception
{
checkRoomForNewUser();
testIllegalUserName(userName);
if (getUser(userName)!=null)
throw new UserExistsException();
}
public void checkRoomForNewUser () throws Exception
{
Connection connection = openConnection();
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.ROOM_FOR_NEW_USER));
ResultSet results = statement.executeQuery();
if (results.next())
{
boolean hasRoom = results.getBoolean("room");
if (hasRoom)
return;
}
throw new PublicMessageException("No room for new users");
}
finally
{
closeConnection(connection);
}
}
public Integer getUserId (String userName) throws IOException, SQLException
{
return getUser(userName).first;
}
public void createUser(String version, String userName, byte[] v, byte[] s) throws Exception
{
checkRoomForNewUser();
testIllegalUserName(userName);
if (getUser(userName)!=null)
throw new UserExistsException();
Connection connection = openConnection();
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.CREATE_USER));
statement.setString(1, version);
statement.setString(2, userName);
statement.setString(3, Base64.encode(v));
statement.setString(4, Base64.encode(s));
log(statement);
statement.executeUpdate();
}
finally
{
closeConnection(connection);
}
}
public Pair<Integer, Triple<String, byte[], byte[]> > getUser (String userName) throws IOException, SQLException
{
Connection connection = openConnection();
Pair<Integer, Triple<String, byte[], byte[]>> result = null;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_USER));
statement.setString(1, userName);
log(statement);
ResultSet results = statement.executeQuery();
if (results.next())
{
result =
new Pair<Integer, Triple<String, byte[], byte[] > >(
results.getInt("id"),
new Triple<String, byte[], byte[]> (
results.getString("version"),
Base64.decode(results.getString("v")),
Base64.decode(results.getString("s"))
)
);
}
}
finally
{
closeConnection(connection);
}
return result;
}
public Triple<String, BigInteger, BigInteger> getVVS (String userName) throws IOException, SQLException
{
Triple<String, byte[], byte[]> vvs = getUser(userName).second;
return
new Triple<String, BigInteger, BigInteger>(
vvs.first,
new BigInteger (vvs.second),
new BigInteger (vvs.third)
);
}
protected byte[] setMailBlock (String userName, byte[] block) throws IOException, SQLException
{
Integer id = getUser(userName).first;
Connection connection = openConnection();
byte[] result = null;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.SET_USER_MAIL_BLOCK));
statement.setInt(1, id);
statement.setString (2, Base64.encode(block));
log(statement);
statement.executeUpdate();
}
finally
{
closeConnection(connection);
}
return result;
}
abstract public byte[] setBlock (String userName, byte[] block) throws IOException, SQLException, CryptoException;
abstract public byte[] getBlock (String userName) throws IOException, SQLException, CryptoException;
protected byte[] setKeyBlock (String userName, byte[] block) throws IOException, SQLException
{
Integer id = getUser(userName).first;
Connection connection = openConnection();
byte[] result = null;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.SET_USER_KEY_BLOCK));
statement.setInt(1, id);
statement.setString (2, Base64.encode(block));
log(statement);
statement.executeUpdate();
}
finally
{
closeConnection(connection);
}
return result;
}
protected byte[] getMailBlock (String userName) throws IOException, SQLException
{
Connection connection = openConnection();
byte[] result = null;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_USER_MAIL_BLOCK));
statement.setString(1, userName);
log(statement);
ResultSet results = statement.executeQuery();
if (results.next())
result = Base64.decode(results.getString("block"));
}
finally
{
closeConnection(connection);
}
return result;
}
public byte[] getDeletedMailBlock(String userName) throws IOException, SQLException
{
Connection connection = openConnection();
byte[] result = null;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_DELETED_USER_MAIL_BLOCK));
statement.setString(1, userName);
log(statement);
ResultSet results = statement.executeQuery();
if (results.next())
result = Base64.decode(results.getString("block"));
}
finally
{
closeConnection(connection);
}
return result;
}
public String getDeletedUser() throws IOException, SQLException
{
Connection connection = openConnection();
String result = null;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_DELETED_USER));
log(statement);
ResultSet results = statement.executeQuery();
if (results.next())
result = results.getString("name");
}
finally
{
closeConnection(connection);
}
return result;
}
protected byte[] getKeyBlock (String userName) throws IOException, SQLException
{
Connection connection = openConnection();
byte[] result = null;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_USER_KEY_BLOCK));
statement.setString(1, userName);
log(statement);
ResultSet results = statement.executeQuery();
if (results.next())
result = Base64.decode(results.getString("block"));
}
finally
{
closeConnection(connection);
}
return result;
}
public void ensureTables() throws SQLException, IOException
{
Connection connection = openConnection();
try
{
for (String sql : catalog.getMulti(catalog.CREATE_TABLES))
{
PreparedStatement statement = connection.prepareStatement (sql);
log(statement);
statement.executeUpdate();
}
}
finally
{
closeConnection(connection);
}
}
public void rateLimitFailure (String userName) throws SQLException, IOException
{
Connection connection = openConnection();
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_LAST_FAILURE));
statement.setString(1, userName);
log(statement);
ResultSet rs = statement.executeQuery();
if (rs.next())
{
Timestamp timeStamp = rs.getTimestamp("mark");
Date now = new Date();
if (now.getTime() - timeStamp.getTime() < catalog.FAILURE_TIMEOUT_SECONDS * 1000)
throw new PublicMessageException ("Too many failures, try again later.");
}
}
finally
{
closeConnection(connection);
}
}
public void markFailure (String userName) throws SQLException, IOException
{
Connection connection = openConnection();
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.MARK_FAILURE));
statement.setString(1, userName);
statement.executeUpdate();
}
finally
{
closeConnection(connection);
}
}
public void deleteUser(String userName) throws IOException, SQLException
{
Connection connection = openConnection();
try
{
String[] texts = catalog.getMulti(catalog.DELETE);
for (String text : texts)
{
PreparedStatement statement = connection.prepareStatement (text);
statement.setString(1, userName);
log(statement);
statement.executeUpdate();
}
}
finally
{
closeConnection(connection);
}
}
public void expungeUser(String userName) throws IOException, SQLException
{
Connection connection = openConnection();
try
{
String[] texts = catalog.getMulti(catalog.EXPUNGE);
for (String text : texts)
{
PreparedStatement statement = connection.prepareStatement (text);
statement.setString(1, userName);
statement.executeUpdate();
}
}
finally
{
closeConnection(connection);
}
}
public Connection openConnection () throws IOException, SQLException
{
log.debug("Connecting to", catalog.CONNECTION_STRING);
return DriverManager.getConnection(catalog.CONNECTION_STRING, catalog.USER, Passwords.getPasswordFor(catalog.USER));
}
public void closeConnection (Connection connection)
{
try
{
if (connection != null)
connection.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void log (Statement sql)
{
System.out.println (sql);
}
protected void testIllegalUserName(String userName) throws Exception
{
// http://www.ietf.org/rfc/rfc2142.txt
final String[] illegalStartsWith = {
"info",
"marketing",
"sales",
"support",
"abuse",
"noc",
"security",
"postmaster",
"hostmaster",
"usenet",
"news",
"webmaster",
"www",
"uucp",
"ftp",
"admin",
"system",
"root",
"test",
"root",
"hostma",
"web",
"post",
"mail",
};
final String[] illegalParts = {
"postmaster",
"webmaster",
"root",
"admin",
"system",
};
String username = userName.toLowerCase();
for (String illegal : illegalParts)
{
if (username.indexOf(illegal) != -1)
throw new Exception("Illegal username");
}
for (String illegal : illegalStartsWith)
{
if (username.startsWith(illegal))
throw new Exception("Illegal username");
}
}
}

View File

@ -0,0 +1,51 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.server.srp.db.sql;
import java.io.IOException;
import java.sql.SQLException;
import core.constants.ConstantsServer;
import core.util.Passwords;
import core.util.SqlCatalog;
import core.util.Streams;
public final class Catalog extends SqlCatalog
{
public String CONNECTION_STRING = ConstantsServer.DBCONNECTION_PREFIX + "mail";
public String USER = "mail";
public int FAILURE_TIMEOUT_SECONDS = 60;
public final String
CREATE_TABLES = "create_tables",
CREATE_USER = "create_user",
GET_USER = "get_user",
GET_USER_MAIL_BLOCK = "get_user_mail_block",
SET_USER_MAIL_BLOCK = "set_user_mail_block",
GET_USER_KEY_BLOCK = "get_user_key_block",
SET_USER_KEY_BLOCK = "set_user_key_block",
GET_LAST_FAILURE = "get_last_failure",
MARK_FAILURE = "mark_failure",
DELETE = "delete_user.sql",
EXPUNGE = "expunge_deleted_user.sql",
GET_DELETED_USER = "get_deleted_user.sql",
GET_DELETED_USER_MAIL_BLOCK = "get_deleted_user_mail_block.sql",
ROOM_FOR_NEW_USER = "room_for_new_user";
public Catalog ()
{
}
public String getPassword () throws IOException
{
return Passwords.getPasswordFor(USER);
}
}

View File

@ -0,0 +1,55 @@
CREATE TABLE IF NOT EXISTS registry (
k VARCHAR(50),
v VARCHAR(255),
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (k)
);
INSERT IGNORE INTO registry (k,v) VALUES ("max_users", "1000");
CREATE TABLE IF NOT EXISTS user (
version VARCHAR(50),
id INTEGER AUTO_INCREMENT,
name VARCHAR(255) COLLATE utf8_general_ci NOT NULL DEFAULT '',
v TEXT,
s TEXT,
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (name),
UNIQUE KEY (id)
);
CREATE TABLE IF NOT EXISTS mail_block (
user_id INTEGER,
block TEXT,
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id)
);
CREATE TABLE IF NOT EXISTS key_block (
user_id INTEGER,
block TEXT,
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id)
);
CREATE TABLE IF NOT EXISTS failure (
user_id INTEGER,
mark TIMESTAMP,
PRIMARY KEY (user_id)
);
CREATE TABLE IF NOT EXISTS deleted_user (
version VARCHAR(50),
id INTEGER AUTO_INCREMENT,
name VARCHAR(255) COLLATE utf8_general_ci NOT NULL DEFAULT '',
v TEXT,
s TEXT,
mark TIMESTAMP NULL DEFAULT NULL,
deleted TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS deleted_mail_block LIKE mail_block;
CREATE TABLE IF NOT EXISTS deleted_key_block LIKE key_block;
DROP TABLE IF EXISTS metadata;

View File

@ -0,0 +1 @@
INSERT INTO user (version, name, v, s) VALUES (?, ?, ?, ?)

View File

@ -0,0 +1,24 @@
REPLACE INTO deleted_mail_block
SELECT mail_block.*
FROM mail_block, user
WHERE user.name=? AND mail_block.user_id = user.id;
REPLACE INTO deleted_key_block
SELECT key_block.*
FROM key_block, user
WHERE user.name=? AND key_block.user_id = user.id;
REPLACE INTO deleted_user(version, id, name, v, s, mark)
SELECT version, id, name, v, s, mark
FROM user
WHERE user.name=?;
DELETE mail_block.*
FROM mail_block, user
WHERE user.name=? AND mail_block.user_id = user.id;
DELETE key_block.*
FROM key_block, user
WHERE user.name=? AND key_block.user_id = user.id;
DELETE FROM user WHERE user.name=?

View File

@ -0,0 +1,9 @@
DELETE deleted_mail_block.*
FROM deleted_mail_block, deleted_user
WHERE deleted_user.name=? AND deleted_mail_block.user_id = deleted_user.id;
DELETE deleted_key_block.*
FROM deleted_key_block, deleted_user
WHERE deleted_user.name=? AND deleted_key_block.user_id = deleted_user.id;
DELETE FROM deleted_user WHERE deleted_user.name=?

View File

@ -0,0 +1,7 @@
select
*
from
deleted_user
order by
deleted
limit 1

View File

@ -0,0 +1,8 @@
SELECT
deleted_mail_block.*
FROM
deleted_user,
deleted_mail_block
WHERE
deleted_mail_block.user_id = deleted_user.id AND
deleted_user.name = ?

View File

@ -0,0 +1,8 @@
SELECT
failure.mark
FROM
user,
failure
WHERE
user.name = ? AND
failure.user_id = user.id

View File

@ -0,0 +1,6 @@
SELECT
*
FROM
user
WHERE
user.name = ?

View File

@ -0,0 +1,8 @@
SELECT
key_block.*
FROM
user,
key_block
WHERE
key_block.user_id = user.id AND
user.name = ?

View File

@ -0,0 +1,8 @@
SELECT
mail_block.*
FROM
user,
mail_block
WHERE
mail_block.user_id = user.id AND
user.name = ?

View File

@ -0,0 +1,8 @@
REPLACE INTO failure (user_id, mark)
SELECT
id as user_id,
now() as mark
FROM
user
WHERE
name = ?

View File

@ -0,0 +1,4 @@
select
count(*) < (select convert(v, unsigned integer) from registry where k="max_users") as room
from
user

View File

@ -0,0 +1 @@
REPLACE INTO key_block (user_id, block) VALUES (?, ?)

View File

@ -0,0 +1 @@
REPLACE INTO mail_block (user_id, block) VALUES (?, ?)

View File

@ -0,0 +1,51 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.server.log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Date;
public class Tail
{
static final int TAIL_INTERVAL = 1000;
String fileName;
String lastTail;
Date lastTailTime;
public Tail (String fileName)
{
this.fileName = fileName;
}
public String getTail () throws IOException
{
Date now = new Date();
if (lastTailTime != null &&
now.getTime() < lastTailTime.getTime() + TAIL_INTERVAL)
return lastTail;
lastTailTime = now;
lastTail = null;
File file = new File(fileName);
RandomAccessFile fileHandler = new RandomAccessFile( file, "r" );
long fileLength = file.length() - 1;
long blockLength = Math.min(fileLength, 4096);
fileHandler.seek(fileLength - blockLength);
byte[] bytes = new byte[(int) blockLength];
fileHandler.readFully(bytes);
fileHandler.close();
lastTail = new String(bytes, "UTF-8");
return lastTail;
}
}

View File

@ -0,0 +1,220 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.server.mailextra;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.bc.util.Strings;
import org.json.JSONException;
import org.json.JSONObject;
import core.util.Base64;
import core.constants.ConstantsPushNotifications;
import core.crypt.HashSha256;
import core.server.mailextra.sql.Catalog;
import core.util.LogOut;
import core.util.Pair;
import core.util.Passwords;
import core.util.Triple;
public class MailExtraDb
{
LogOut log = new LogOut(MailExtraDb.class);
Catalog catalog = new Catalog();
public String getUserHash (String email)
{
HashSha256 hasher = new HashSha256();
return Base64.encode(hasher.hash(Strings.toByteArray(email.toLowerCase())));
}
public Triple<String,String,String> getDeviceFor (String email) throws SQLException, IOException
{
return getDeviceForHash(getUserHash(email));
}
public Triple<String,String,String> getDeviceForHash (String hash) throws SQLException, IOException
{
Connection connection = openConnection();
Triple<String,String,String> result;
try
{
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.GET_NOTIFICATIONS_FOR));
statement.setString(1, hash);
log.debug(statement);
ResultSet rs = statement.executeQuery();
if (!rs.next())
return null;
result = new Triple<String,String,String>(rs.getString("notification_type"), rs.getString("device_type"), rs.getString("device_id"));
}
finally
{
closeConnection(connection);
}
return result;
}
public void setNotificationsFor (String email, String notificationType, String deviceType, String deviceId) throws SQLException, IOException
{
setNotificationsFor (getUserHash(email), deviceType, deviceId, notificationType);
}
public void setNotificationsForHash (String hash, String notificationType, String deviceType, String deviceId) throws SQLException, IOException
{
Connection connection = openConnection();
try
{
String statements[] = catalog.getMulti(Catalog.SET_NOTIFICATIONS_FOR);
boolean first = true;
for (String s : statements)
{
PreparedStatement statement = connection.prepareStatement (s);
if (first)
{
statement.setString(1, hash);
statement.setString(2, notificationType);
statement.setString(3, deviceType);
statement.setString(4, deviceId);
}
log.debug(statement);
statement.executeUpdate();
first = false;
}
}
finally
{
closeConnection(connection);
}
}
public void addDaysTo (String email, int days) throws SQLException, IOException
{
Connection connection = openConnection();
try
{
String statements[] = catalog.getMulti(Catalog.ADD_DAYS_TO);
boolean first = true;
for (String s : statements)
{
PreparedStatement statement = connection.prepareStatement (s);
if (first)
{
statement.setString(1, email);
statement.setInt(2, days);
}
log.debug(statement);
statement.executeUpdate();
first = false;
}
}
finally
{
closeConnection(connection);
}
}
public int getDaysLeft (String email) throws SQLException, IOException
{
Connection connection = openConnection();
try
{
log.debug(catalog.getSingle(Catalog.GET_DAYS_LEFT));
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.GET_DAYS_LEFT));
statement.setString(1, email);
log.debug(statement);
ResultSet rs = statement.executeQuery();
if (!rs.next())
throw new IOException ("No results");
int days = rs.getInt("days");
rs.close();
return days;
}
finally
{
closeConnection(connection);
}
}
public void ensureTables() throws SQLException, IOException
{
Connection connection = openConnection();
try
{
for (String sql : catalog.getMulti(Catalog.CREATE_TABLES))
{
PreparedStatement statement = connection.prepareStatement (sql);
log.debug(statement);
statement.executeUpdate();
}
}
finally
{
closeConnection(connection);
}
}
public Connection openConnection () throws SQLException, IOException
{
return DriverManager.getConnection(Catalog.CONNECTION_STRING, Catalog.USER, Passwords.getPasswordFor(Catalog.USER));
}
public void closeConnection (Connection connection)
{
try
{
if (connection != null)
connection.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void handlePushNotificationsJson(JSONObject json) throws JSONException, SQLException, IOException
{
String user = json.getString(ConstantsPushNotifications.USER);
setNotificationsForHash(
user,
json.getString(ConstantsPushNotifications.NOTIFICATION_TYPE),
json.has(ConstantsPushNotifications.DEVICE_TYPE) ?
json.getString(ConstantsPushNotifications.DEVICE_TYPE) : null,
json.has(ConstantsPushNotifications.DEVICE_ID) ?
json.getString(ConstantsPushNotifications.DEVICE_ID) : null
);
}
public void removeDevice(String deviceType, String deviceId)
{
}
}

View File

@ -0,0 +1,25 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.server.mailextra.sql;
import java.io.IOException;
import core.util.SqlCatalog;
import core.util.Streams;
public class Catalog extends SqlCatalog
{
static public final String CONNECTION_STRING = "jdbc:mysql://localhost/mail_extra";
public static final String USER = "mail_extra";
static public final String GET_NOTIFICATIONS_FOR = "get_notifications_for.sql";
static public final String SET_NOTIFICATIONS_FOR = "set_notifications_for.sql";
static public final String PRUNE_DEVICES = "prune_devices.sql";
static public final String CREATE_TABLES = "create_tables";
static public final String ADD_DAYS_TO = "add_days_to";
static public final String GET_DAYS_LEFT = "get_days_left";
}

View File

@ -0,0 +1,10 @@
SET @email = ?, @days = ?;
INSERT INTO expirations (email, expiration) VALUES(@email, DATE_ADD(CURDATE(), INTERVAL @days DAY))
ON DUPLICATE KEY UPDATE
expiration =
IF(
DATEDIFF(expiration, CURDATE())>0,
DATE_ADD(expiration, INTERVAL @days DAY),
VALUES(expiration)
)

View File

@ -0,0 +1,15 @@
CREATE TABLE IF NOT EXISTS expirations (
email VARCHAR(255) NOT NULL,
expiration DATE NOT NULL,
PRIMARY KEY (email)
);
CREATE TABLE IF NOT EXISTS `device` (
`email` VARCHAR(255) NOT NULL,
`notification_type` ENUM('NONE','SHORT','LONG') NOT NULL,
`device_type` VARCHAR(255) DEFAULT NULL,
`device_id` VARCHAR(255) DEFAULT NULL,
`mark` date NOT NULL,
PRIMARY KEY (`email`),
KEY `device` (`device_type`,`device_id`)
);

View File

@ -0,0 +1,6 @@
SELECT
DATEDIFF(expiration, CURDATE()) as days
FROM
expirations
WHERE
expirations.email = ?

View File

@ -0,0 +1,10 @@
SELECT
device.notification_type,
device.device_type,
device.device_id,
device.mark
FROM
device
WHERE
device.email = ?

View File

@ -0,0 +1,4 @@
SET @email = ?, @notification_type = ?, @device_type = ?, @device_id = ?;
DELETE FROM device WHERE device_type = @device_type AND device_id = @device_id;
REPLACE INTO device (email, device_type, device_id, notification_type, mark) VALUES(@email, @device_type, @device_id, @notification_type, now())

View File

@ -0,0 +1,301 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp;
import java.math.BigInteger;
import core.util.Base64;
import org.json.JSONObject;
import core.util.CallSingle;
import core.util.JSONRegistry;
import core.util.Strings;
public class SRPPacketSerializerJSON
{
static public void register () {}
static {
JSONRegistry.register (
"core.srp.SRPPackets$Packet1_ClientSendsHello",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.Packet1_ClientSendsHello p = (SRPPackets.Packet1_ClientSendsHello)v;
object.put("user", p.user);
object.put("version", p.version);
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new SRPPackets.Packet1_ClientSendsHello(
v.get("user").toString(),
v.get("version").toString()
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$Packet2_ServerSendSalt",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.Packet2_ServerSendSalt p = (SRPPackets.Packet2_ServerSendSalt)v;
object.put("salt", Base64.encode(p.salt));
object.put("version", p.version);
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new SRPPackets.Packet2_ServerSendSalt(
v.get("version").toString(),
Base64.decode(v.get("salt").toString())
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$Packet3_ClientSendPublicKey",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.Packet3_ClientSendPublicKey p = (SRPPackets.Packet3_ClientSendPublicKey)v;
object.put("publicKey", new String(Base64.encode(p.publicKey)));
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new SRPPackets.Packet3_ClientSendPublicKey(
Base64.decode(v.get("publicKey").toString())
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$Packet4_ServerSendPublicKey",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.Packet4_ServerSendPublicKey p = (SRPPackets.Packet4_ServerSendPublicKey)v;
object.put("publicKey", new String(Base64.encode(p.publicKey)));
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new SRPPackets.Packet4_ServerSendPublicKey(
new BigInteger(Base64.decode(v.get("publicKey").toString()))
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$Packet5_ClientSendEvidence",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.Packet5_ClientSendEvidence p = (SRPPackets.Packet5_ClientSendEvidence)v;
object.put("evidence", new String(Base64.encode(p.evidence)));
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new SRPPackets.Packet5_ClientSendEvidence(
Base64.decode(v.get("evidence").toString())
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$Packet6_ServerSendEvidenceAndPayload",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.Packet6_ServerSendEvidenceAndPayload p = (SRPPackets.Packet6_ServerSendEvidenceAndPayload)v;
object.put("evidence", new String(Base64.encode(p.evidence)));
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new SRPPackets.Packet6_ServerSendEvidenceAndPayload(
new BigInteger(Base64.decode(v.get("evidence").toString()))
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$PacketInit_ClientTestCreate",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.PacketInit_ClientTestCreate p = (SRPPackets.PacketInit_ClientTestCreate)v;
object.put("user", p.user);
object.put("version", p.version);
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new
SRPPackets.PacketInit_ClientTestCreate(
v.getString("version"),
v.getString("user")
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$PacketInit_EncryptedPacket",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.PacketInit_EncryptedPacket p = (SRPPackets.PacketInit_EncryptedPacket)v;
object.put("encryptedBlock", new String(Base64.encode(p.encryptedBlock)));
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new
SRPPackets.PacketInit_EncryptedPacket(
Base64.decode(v.getString("encryptedBlock"))
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$PacketInit_ServerResponse",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.PacketInit_ServerResponse p = (SRPPackets.PacketInit_ServerResponse)v;
object.put("succeeded", p.succeeded);
object.put("reason", p.reason);
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
return new
SRPPackets.PacketInit_ServerResponse(
v.getBoolean("succeeded"),
v.has("reason") ? v.getString("reason") : null
);
}
}
);
JSONRegistry.register (
"core.srp.SRPPackets$PacketInit_ClientPreAutheticationInitialization",
new CallSingle<JSONObject,Object> () {
@Override
public JSONObject invoke(Object v) throws Exception
{
JSONObject object = new JSONObject();
SRPPackets.PacketInit_ClientPreAutheticationInitialization p = (SRPPackets.PacketInit_ClientPreAutheticationInitialization)v;
object.put("version", p.version);
object.put("user", p.user);
object.put("s", new String(Base64.encode(p.s)));
object.put("v", new String(Base64.encode(p.v)));
if (p.extra != null)
object.put("extra", new String(Base64.encode(p.extra)));
return object;
}
},
new CallSingle<Object,JSONObject> () {
@Override
public Object invoke(JSONObject v) throws Exception
{
SRPPackets.PacketInit_ClientPreAutheticationInitialization p =
new SRPPackets.PacketInit_ClientPreAutheticationInitialization(
v.getString("version"),
v.getString("user"),
Base64.decode(v.getString("v")),
Base64.decode(v.getString("s"))
);
if (v.has("extra"))
p.extra = Base64.decode(v.getString("extra"));
return p;
}
}
);
}
}

View File

@ -0,0 +1,182 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp;
import java.math.BigInteger;
import core.callback.Callback;
import core.callback.CallbackDefault;
public class SRPPackets
{
public static void register () { }
static {
SRPPacketSerializerJSON.register();
}
public static class PacketInit_ClientTestCreate
{
public String version;
public String user;
public PacketInit_ClientTestCreate(String version, String user)
{
this.version = version;
this.user = user;
}
}
public static class PacketInit_ClientPreAutheticationInitialization
{
public String user;
public byte[] v;
public byte[] s;
public byte[] extra;
public String version;
public PacketInit_ClientPreAutheticationInitialization(String version, String user, byte[] v, byte[] s)
{
this.version = version;
this.user = user;
this.v = v;
this.s = s;
extra = null;
}
}
public static class PacketInit_EncryptedPacket
{
public byte[] encryptedBlock;
public PacketInit_EncryptedPacket (byte[] encryptedBlock)
{
this.encryptedBlock = encryptedBlock;
}
public static Callback wrap_()
{
return new CallbackDefault() {
@Override
public void onSuccess(Object... arguments) throws Exception {
callback.invoke(new PacketInit_EncryptedPacket((byte[])(arguments[0])));
}
};
}
public static Callback unwrap_()
{
return new CallbackDefault() {
@Override
public void onSuccess(Object... arguments) throws Exception {
PacketInit_EncryptedPacket packet = (PacketInit_EncryptedPacket)(arguments[0]);
callback.invoke(packet.encryptedBlock);
}
};
}
}
public static class PacketInit_ServerResponse
{
public boolean succeeded;
public String reason;
public PacketInit_ServerResponse(boolean succeeded, String reason)
{
this.succeeded = succeeded;
this.reason = reason;
}
}
public static class Packet1_ClientSendsHello
{
public String user;
public String version;
public Packet1_ClientSendsHello (String user, String version)
{
this.user = user;
this.version = version;
}
}
public static class Packet2_ServerSendSalt
{
public byte[] salt;
public String version;
public Packet2_ServerSendSalt (String version, byte[] salt)
{
this.salt = salt;
this.version = version;
}
public byte[] getSalt ()
{
return salt;
}
}
public static class Packet3_ClientSendPublicKey
{
public byte[] publicKey;
public Packet3_ClientSendPublicKey (byte[] publicKey)
{
this.publicKey = publicKey;
}
public byte[] getPublicKey ()
{
return publicKey;
}
}
public static class Packet4_ServerSendPublicKey
{
public byte[] publicKey;
public Packet4_ServerSendPublicKey (BigInteger publicKey)
{
this.publicKey = publicKey.toByteArray();
}
public byte[] getPublicKey ()
{
return publicKey;
}
}
public static class Packet5_ClientSendEvidence
{
public byte[] evidence;
public Packet5_ClientSendEvidence (byte[] evidence)
{
this.evidence = evidence;
}
public byte[] getEvidence ()
{
return evidence;
}
}
public static class Packet6_ServerSendEvidenceAndPayload
{
public byte[] evidence;
public Packet6_ServerSendEvidenceAndPayload (BigInteger evidence)
{
this.evidence = evidence.toByteArray();
}
public byte[] getEvidence ()
{
return evidence;
}
}
}

View File

@ -0,0 +1,43 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp;
import core.crypt.Cryptor;
import core.crypt.CryptorAES;
import core.exceptions.CryptoException;
public class SRPSession
{
protected byte[] sessionKey;
public byte[] streamDecrypt (byte[] bytes) throws CryptoException
{
try
{
Cryptor cryptor = new CryptorAES(sessionKey);
return cryptor.decrypt(bytes);
}
catch (Exception e)
{
e.printStackTrace();
throw new CryptoException(e);
}
}
public byte[] streamEncrypt (byte[] bytes) throws CryptoException
{
try
{
Cryptor cryptor = new CryptorAES(sessionKey);
return cryptor.encrypt(bytes);
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
}

View File

@ -0,0 +1,91 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.client;
import core.callback.Callback;
import com.jordanzimmerman.SRPClientSession;
import com.jordanzimmerman.SRPFactory;
import com.jordanzimmerman.SRPVerifier;
import core.callback.CallbackDefault;
import core.callbacks.JSONSerialize;
import core.callbacks.IoSend;
import core.crypt.KeyPairFromPassword;
import core.exceptions.CryptoException;
import core.io.IoChain;
import core.srp.SRPPackets;
import core.srp.SRPSession;
public class SRPClient extends SRPSession
{
static { SRPPackets.register(); }
SRPFactory factory;
SRPClientAsync session;
public SRPClient (byte[] password)
{
session = new SRPClientAsync(password);
}
public static SRPVerifier createVerifierFromKeyPair (KeyPairFromPassword keyPair) throws CryptoException
{
SRPFactory factory = SRPFactory.getInstance();
SRPVerifier verifier = factory.makeVerifier(keyPair.getVerifier());
return verifier;
}
public SRPPackets.Packet1_ClientSendsHello step1_generateHello (String user, String version)
{
return new SRPPackets.Packet1_ClientSendsHello(user, version);
}
public Callback step2_generatePublicKey_send_ (SRPPackets.Packet2_ServerSendSalt packet, IoChain sender)
{
return
session.setSalt_(packet.getSalt())
.addCallback(
new CallbackDefault() {
public void onSuccess(Object...arguments) {
next(new SRPPackets.Packet3_ClientSendPublicKey(session.getPublicKey()));
}
}
)
.addCallback(new JSONSerialize())
.addCallback(new IoSend(sender));
}
public Callback step3_generateEvidenceUsingServerProvidedInputs_send (SRPPackets.Packet4_ServerSendPublicKey packet, IoChain sender) throws CryptoException
{
return
session.setServerPublicKey_(packet.getPublicKey())
.addCallback(
new CallbackDefault() {
public void onSuccess(Object...arguments) {
next(new SRPPackets.Packet5_ClientSendEvidence(session.getEvidenceValue()));
}
}
)
.addCallback(new JSONSerialize())
.addCallback(new IoSend(sender));
}
public Callback step4_validateServerEvidence (SRPPackets.Packet6_ServerSendEvidenceAndPayload packet) throws CryptoException
{
return
session.validateServerEvidenceValue_M2_(packet.getEvidence())
.addCallback(
new CallbackDefault() {
public void onSuccess(Object...arguments) {
sessionKey = session.getSessionKey();
next(sessionKey);
}
}
);
}
}

View File

@ -0,0 +1,71 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.client;
import com.jordanzimmerman.SRPClientSession;
import com.jordanzimmerman.SRPFactory;
import core.util.Base64;
import core.callback.Callback;
import core.callback.CallbackDefault;
public class SRPClientAsync
{
SRPClientSession key;
public SRPClientAsync (byte[] password)
{
key = SRPFactory.getInstance().newClientSession(password);
}
public Callback setSalt_(byte[] bs)
{
return new CallbackDefault(bs)
{
public void onSuccess(Object... arguments) throws Exception {
key.setSalt_s((byte[])V(0));
callback.invoke();
}
};
}
public Callback setServerPublicKey_(byte[] publicKey)
{
return new CallbackDefault(publicKey)
{
public void onSuccess(Object... arguments) throws Exception {
key.setServerPublicKey_B((byte[])V(0));
callback.invoke();
}
};
}
public Callback validateServerEvidenceValue_M2_(byte[] evidence)
{
return new CallbackDefault(evidence)
{
public void onSuccess(Object... arguments) throws Exception {
key.validateServerEvidenceValue_M2((byte[])V(0));
callback.invoke();
}
};
}
public byte[] getSessionKey()
{
return key.getSessionKey_K();
}
public byte[] getPublicKey()
{
return key.getPublicKey_A_();
}
public byte[] getEvidenceValue()
{
return key.getEvidenceValue_M1_();
}
}

View File

@ -0,0 +1,10 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.client;
public interface SRPClientListener {
public void onSRPStep (String stepName);
}

View File

@ -0,0 +1,93 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.client;
import core.callbacks.IoOpen;
import core.constants.ConstantsVersion;
import core.crypt.KeyPairFromPassword;
import core.exceptions.CryptoException;
import core.io.IoChain;
import core.srp.SRPPackets;
import core.util.SimpleSerializer;
public class SRPClientUserSession extends IoChain
{
String user;
KeyPairFromPassword keyPair;
SRPClient srp;
SRPClientListener listener;
int step;
public SRPClientUserSession (String user, KeyPairFromPassword keyPair, IoChain sender, SRPClientListener listener) throws CryptoException
{
super(sender);
this.user = user;
this.keyPair = keyPair;
this.listener = listener;
}
@Override
public void open () throws Exception
{
if (listener != null)
listener.onSRPStep("H");
step = 0;
this.srp = new SRPClient(keyPair.getVerifier());
sender.send(SimpleSerializer.serialize(new SRPPackets.Packet1_ClientSendsHello(user, ConstantsVersion.LOGIN)));
}
@Override
protected void onReceive(byte[] bytes) throws Exception
{
switch (step++)
{
case 0:
{
if (listener != null)
listener.onSRPStep("" + step);
SRPPackets.Packet2_ServerSendSalt in = SimpleSerializer.deserialize(bytes);
srp.step2_generatePublicKey_send_(in, sender).invoke();
} break;
case 1:
{
if (listener != null)
listener.onSRPStep("" + step);
SRPPackets.Packet4_ServerSendPublicKey in = SimpleSerializer.deserialize(bytes);
srp.step3_generateEvidenceUsingServerProvidedInputs_send(in, sender).invoke();
} break;
case 2:
{
if (listener != null)
listener.onSRPStep("" + step);
SRPPackets.Packet6_ServerSendEvidenceAndPayload in = SimpleSerializer.deserialize(bytes);
srp.step4_validateServerEvidence(in).addCallback(new IoOpen(receiver)).invoke();
} break;
default:
if (listener != null)
listener.onSRPStep("R");
super.onReceive(srp.streamDecrypt(bytes));
}
}
@Override
public void send(byte[] packet) throws Exception
{
if (listener != null)
listener.onSRPStep("S");
sender.send(srp.streamEncrypt(packet));
}
}

View File

@ -0,0 +1,77 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.server;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.bc.crypto.params.KeyParameter;
import com.jordanzimmerman.SRPFactory;
import com.jordanzimmerman.SRPServerSession;
import com.jordanzimmerman.SRPVerifier;
import core.exceptions.CryptoException;
import core.srp.SRPPackets;
import core.srp.SRPSession;
import core.srp.SRPPackets.Packet2_ServerSendSalt;
import core.srp.SRPPackets.Packet3_ClientSendPublicKey;
import core.srp.SRPPackets.Packet4_ServerSendPublicKey;
import core.srp.SRPPackets.Packet5_ClientSendEvidence;
import core.srp.SRPPackets.Packet6_ServerSendEvidenceAndPayload;
public class SRPServer extends SRPSession
{
static { SRPPackets.register(); }
SRPFactory factory;
SRPServerSession session;
public SRPServer ()
{
factory = SRPFactory.getInstance();
}
public SRPPackets.Packet2_ServerSendSalt step1_getSalt_send (String version, BigInteger verifier, BigInteger salt)
{
session = factory.newServerSession(new SRPVerifier (verifier, salt));
return new SRPPackets.Packet2_ServerSendSalt(version, session.getVerifier().salt_s.toByteArray());
}
public SRPPackets.Packet4_ServerSendPublicKey step2_receivePublicKey_generatePublicKey_send (SRPPackets.Packet3_ClientSendPublicKey packet) throws CryptoException
{
try
{
session.setClientPublicKey_A(packet.getPublicKey());
return new SRPPackets.Packet4_ServerSendPublicKey(session.getPublicKey_B());
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
public SRPPackets.Packet6_ServerSendEvidenceAndPayload step3_validateClientEvidence_generateEvidence_send (SRPPackets.Packet5_ClientSendEvidence packet) throws CryptoException
{
try
{
session.computeCommonValue_S();
session.validateClientEvidenceValue_M1(packet.getEvidence());
sessionKey = session.getSessionKey_K();
return new SRPPackets.Packet6_ServerSendEvidenceAndPayload(session.getEvidenceValue_M2());
}
catch (Exception e)
{
throw new CryptoException(e);
}
}
}

View File

@ -0,0 +1,177 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.server;
import java.math.BigInteger;
import core.client.messages.ClientMessagesSerializerJSON;
import core.crypt.CryptorRSAAES;
import core.exceptions.CryptoException;
import core.exceptions.PublicMessageException;
import core.io.IoChain;
import core.srp.SRPPackets;
import core.srp.SRPPackets.PacketInit_ClientTestCreate;
import core.util.LogOut;
import core.util.SimpleSerializer;
import core.util.Strings;
import core.util.Triple;
public class SRPServerUserSession extends IoChain
{
static { SRPPackets.register(); ClientMessagesSerializerJSON.register(); }
LogOut log = new LogOut(SRPServerUserSession.class);
CryptorRSAAES cryptorRSA;
boolean noMoreRoomForUsers = false;
String userName;
SRPServer srp = new SRPServer();
int step = 0;
SRPServerUserSessionDb db;
public SRPServerUserSession (CryptorRSAAES cryptorRSA, SRPServerUserSessionDb db, IoChain session)
{
super(session);
this.db = db;
this.cryptorRSA = cryptorRSA;
}
public String getUserName ()
{
return userName;
}
@Override
public void onReceive (byte[] bytes) throws Exception
{
try
{
if (step == 0)
{
Object object = SimpleSerializer.deserialize(bytes);
if (object instanceof SRPPackets.PacketInit_EncryptedPacket)
{
step = -1;
SRPPackets.PacketInit_EncryptedPacket
block = (SRPPackets.PacketInit_EncryptedPacket)object;
Object packet = SimpleSerializer.deserialize(cryptorRSA.decrypt(block.encryptedBlock));
if (packet instanceof SRPPackets.PacketInit_ClientPreAutheticationInitialization)
{
step_init((SRPPackets.PacketInit_ClientPreAutheticationInitialization)packet);
return;
}
else
if (packet instanceof SRPPackets.PacketInit_ClientTestCreate)
{
step_testcreate((SRPPackets.PacketInit_ClientTestCreate)packet);
return;
}
}
}
switch (step++)
{
case 0:
{
SRPPackets.Packet1_ClientSendsHello packet = SimpleSerializer.deserialize(bytes);
this.userName = packet.user;
db.rateLimitFailure(userName);
Triple<String, BigInteger, BigInteger> vvs = db.getUserVVS(packet.user);
sender.send(SimpleSerializer.serialize(
srp.step1_getSalt_send(vvs.first, vvs.second, vvs.third)
));
}
break;
case 1:
{
SRPPackets.Packet3_ClientSendPublicKey packet = SimpleSerializer.deserialize(bytes);
sender.send(SimpleSerializer.serialize(srp.step2_receivePublicKey_generatePublicKey_send(packet)));
}
break;
case 2:
{
SRPPackets.Packet5_ClientSendEvidence packet = SimpleSerializer.deserialize(bytes);
SRPPackets.Packet6_ServerSendEvidenceAndPayload out =
srp.step3_validateClientEvidence_generateEvidence_send(packet);
sender.send(SimpleSerializer.serialize(out));
super.open();
}
break;
default:
super.onReceive(srp.streamDecrypt(bytes));
}
}
catch (CryptoException e)
{
db.markFailure(userName);
throw e;
}
catch (PublicMessageException e)
{
db.markFailure(userName);
throw e;
}
catch (Exception e)
{
db.markFailure(userName);
throw new CryptoException (e);
}
}
public void step_testcreate(PacketInit_ClientTestCreate packet) throws Exception
{
try
{
db.testCreate (packet.version, packet.user);
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(true, null)));
}
catch (PublicMessageException e)
{
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, e.message)));
}
catch (Exception e)
{
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, null)));
}
stop();
}
public void step_init (SRPPackets.PacketInit_ClientPreAutheticationInitialization packet) throws Exception
{
try
{
db.createUser (packet.version, packet.user, new BigInteger(packet.v), new BigInteger(packet.s), packet.extra);
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(true, null)));
}
catch (PublicMessageException e)
{
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, e.message)));
}
catch (Exception e)
{
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, null)));
}
stop();
}
@Override
public void send(byte[] packet) throws Exception
{
sender.send(srp.streamEncrypt(packet));
}
}

View File

@ -0,0 +1,23 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.server;
import java.math.BigInteger;
import core.util.Pair;
import core.util.Triple;
public interface SRPServerUserSessionDb
{
public void rateLimitFailure (String userName) throws Exception;
public void markFailure (String userName) throws Exception;
public Triple<String, BigInteger, BigInteger> getUserVVS (String userName) throws Exception;
public void testCreate (String version, String userName) throws Exception;
public void createUser (String version, String userName, BigInteger v, BigInteger s, byte[] extra) throws Exception;
}

View File

@ -0,0 +1,57 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.srp.test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Random;
import core.exceptions.CryptoException;
import core.crypt.KeyPairFromPassword;
import core.crypt.KeyPairFromPasswordCryptor;
import core.crypt.PBE;
import core.util.Streams;
public class PBETest
{
public static void main (String[] args) throws CryptoException, IOException
{
Random random = new Random();
String password = "TESTPASSWORD";
String s = "I am a string which is not to short not to long. I really should be much much larger. " +
"but what can I do. I wonder, in reality this string would be a very long random number. ";
for (int i=0; i<50; ++i)
s += BigInteger.valueOf(Math.abs(random.nextLong())).toString(32);
KeyPairFromPassword keyPair = new KeyPairFromPassword(password);
KeyPairFromPasswordCryptor cryptor = new KeyPairFromPasswordCryptor(keyPair);
byte[] verifier = keyPair.getVerifier();
System.out.println(new BigInteger(verifier));
byte[] e = cryptor.encrypt(s.getBytes());
FileOutputStream fe = new FileOutputStream("PBETest.enc");
fe.write(e);
fe.flush();
FileOutputStream fp = new FileOutputStream("PBETest.plain");
fp.write(e);
fp.flush();
byte[] in = Streams.readFullyBytes(new FileInputStream("PBETest.enc"));
String match = new String(cryptor.decrypt(in));
if (match.equals(s))
System.out.println("decryption succeeded");
}
}

View File

@ -0,0 +1,31 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.swing;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class CheckListener implements DocumentListener
{
Checker checker;
public CheckListener (Checker checker)
{
this.checker = checker;
}
public void onChange ()
{
SwingUtilities.invokeLater(new Runnable() {
public void run() { checker.onCheck(); }
});
}
public void changedUpdate(DocumentEvent e) { onChange(); }
public void insertUpdate(DocumentEvent e) { onChange(); }
public void removeUpdate(DocumentEvent e) { onChange(); }
}

View File

@ -0,0 +1,11 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.swing;
public interface Checker
{
public void onCheck ();
}

View File

@ -0,0 +1,16 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.swing;
import java.awt.Dimension;
public class DimensionCalculator
{
public Dimension calculate (Dimension dimension)
{
return dimension;
}
}

View File

@ -0,0 +1,38 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.swing;
import java.io.File;
import javax.swing.filechooser.FileFilter;
public class FileFilterStandard extends FileFilter
{
String name, extension;
public FileFilterStandard(String name, String extension)
{
this.name = name;
this.extension = extension;
}
public boolean accept(File f)
{
if (f.isDirectory())
{
return true;
}
return (f.getPath().toLowerCase().endsWith(extension));
}
// The description of this filter
public String getDescription()
{
return name;
}
}

View File

@ -0,0 +1,81 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.swing;
import java.awt.TextArea;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class RedirectStreams
{
JTextArea textArea;
PrintStream savedOutput;
PrintStream savedError;
PrintStream out;
public RedirectStreams(JTextArea textArea)
{
this.textArea = textArea;
OutputStream os =
new OutputStream() {
@Override
public void write(int b) throws IOException
{
updateTextArea(String.valueOf((char) b));
}
@Override
public void write(byte[] b, int off, int len) throws IOException
{
updateTextArea(new String(b, off, len));
}
@Override
public void write(byte[] b) throws IOException
{
write(b, 0, b.length);
}
};
out = new PrintStream(os, true);
}
private void updateTextArea(final String text)
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
textArea.append(text);
}
});
}
public void redirectSystem()
{
savedOutput = System.out;
savedError = System.err;
System.setOut(out);
System.setErr(out);
}
public PrintStream getOut ()
{
return out;
}
public void restoreSystem ()
{
System.setOut(savedOutput);
System.setErr(savedError);
}
}

View File

@ -0,0 +1,72 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.swing;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.SpringLayout;
public class SpringLayoutSize extends SpringLayout
{
Dimension dimension;
DimensionCalculator dimensionCalculator;
int depth;
public SpringLayoutSize (int depth, Dimension dimension, DimensionCalculator dimensionCalculator)
{
this.dimension = dimension;
this.depth = depth;
this.dimensionCalculator = dimensionCalculator;
}
public SpringLayoutSize (int depth, Dimension dimension)
{
this(depth, dimension, null);
}
public Container getNestedParent(Container parent)
{
for (int i=1; i<depth; ++i)
parent = parent.getParent();
return parent;
}
public Dimension calculateDimension (Container parent)
{
Container nestedParent = getNestedParent (parent);
Dimension result =
new Dimension (
dimension.width > 0 ? dimension.width : nestedParent.getSize().width,
dimension.height > 0 ? dimension.height : nestedParent.getSize().height
);
if (dimensionCalculator != null)
result = dimensionCalculator.calculate(result);
return result;
}
@Override
public Dimension maximumLayoutSize(Container parent)
{
return calculateDimension(parent);
}
@Override
public Dimension minimumLayoutSize(Container parent)
{
return calculateDimension(parent);
}
@Override
public Dimension preferredLayoutSize(Container parent)
{
return calculateDimension(parent);
}
}

View File

@ -0,0 +1,73 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import java.util.ArrayList;
import java.util.List;
public class Arrays
{
public static <T> T firstOrNull (T[] t)
{
if (t != null && t.length > 0)
return t[0];
return null;
}
public static byte[] generate (int length, int j)
{
byte[] v = new byte[length];
for (int i=0; i<length; ++i)
v[i]=(byte)j;
return v;
}
public static byte[] concat (byte[]... arrays)
{
int length = 0;
for (byte[] array : arrays)
length += array.length;
byte[] result = new byte[length];
int i=0;
for (byte[] array : arrays)
{
for (byte b : array)
result[i++] = b;
}
return result;
}
public static byte[] copyOf(byte[] src, int l)
{
return copyOf(src, 0, l);
}
public static void copyFromTo(byte[] src, int srcOff, byte[] dst, int dstOff, int l)
{
for (int i=0; i<l; ++i)
dst[i+dstOff] = src[i+srcOff];
}
public static void copyFromTo(byte[] src, byte[] dst, int l)
{
copyFromTo(src,0, dst,0, l);
}
public static byte[] copyOf(byte[] src, int offset, int l)
{
byte[] result = new byte[l];
for (int i=0; i<l; ++i)
result[i] = src[offset + i];
return result;
}
}

View File

@ -0,0 +1,58 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
public class Base16
{
static String decoder = "0123456789abcdef";
static byte[] encoder = null;
static void initialize ()
{
if (encoder != null)
return;
encoder = new byte[0xFF];
for (int i=0; i<decoder.length(); ++i)
encoder[decoder.charAt(i)] = (byte)i;
}
public static byte[] decode (String value)
{
initialize();
byte[] bytes = new byte[value.length() / 2];
int i=0, j=0;
while (i<value.length())
{
int nibbleHi = (int)encoder[(int)value.charAt(i++)];
int nibbleLo = (int)encoder[(int)value.charAt(i++)];
bytes[j++] = (byte) ((nibbleHi << 4) | (nibbleLo));
}
return bytes;
}
public static String encode (byte[] bytes)
{
String result = "";
int i=0;
while (i<bytes.length)
{
int b = bytes[i++] & 0xFF;
int nibbleLo = b & 0x0F;
int nibbleHi = b >> 4;
result += decoder.charAt(nibbleHi);
result += decoder.charAt(nibbleLo);
}
return result;
}
}

View File

@ -0,0 +1,68 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import core.callback.Callback;
import core.callback.CallbackDefault;
public class Base64
{
public static String encode(byte[] bytes)
{
return Strings.toString(org.bc.util.encoders.Base64.encode(bytes));
}
public static byte[] decode(String b64)
{
return org.bc.util.encoders.Base64.decode(Strings.toBytes(b64));
}
public static byte[] encodeBytes(byte[] bytes)
{
return org.bc.util.encoders.Base64.encode(bytes);
}
public static byte[] decodeBytes(byte[] b64)
{
return org.bc.util.encoders.Base64.decode(b64);
}
public static Callback decode_()
{
return new CallbackDefault() {
public void onSuccess(Object... arguments) throws Exception {
next(Base64.decode((String)arguments[0]));
}
};
}
public static Callback encode_()
{
return new CallbackDefault() {
public void onSuccess(Object... arguments) throws Exception {
next(Base64.encode((byte[])arguments[0]));
}
};
}
public static Callback decodeBytes_()
{
return new CallbackDefault() {
public void onSuccess(Object... arguments) throws Exception {
next(Base64.decodeBytes((byte[])arguments[0]));
}
};
}
public static Callback encodeBytes_()
{
return new CallbackDefault() {
public void onSuccess(Object... arguments) throws Exception {
next(Base64.encodeBytes((byte[])arguments[0]));
}
};
}
}

View File

@ -0,0 +1,20 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import java.io.Serializable;
public class Block implements Serializable
{
private static final long serialVersionUID = 1L;
public byte[] bytes;
public Block (byte[] bytes)
{
this.bytes = bytes;
}
}

View File

@ -0,0 +1,15 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import org.timepedia.exporter.client.Export;
import org.timepedia.exporter.client.Exportable;
@Export
public interface CallSingle<T, V> extends Exportable
{
public T invoke(V v) throws Exception;
}

View File

@ -0,0 +1,24 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import core.util.CallSingle;
abstract class CallSingleWithVariables<T,V> implements CallSingle<T,V>
{
protected Object[] v;
public CallSingleWithVariables(Object... v)
{
this.v = v;
}
@SuppressWarnings("unchecked")
public <T> T V(int i)
{
return (T)v[i];
}
}

View File

@ -0,0 +1,20 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
public class Characters {
public static boolean isWhitespace(char c)
{
return " \t\n\r".indexOf(c)!=-1;
}
public static boolean isNumber(char c)
{
return "0123456789".indexOf(c)!=-1;
}
}

View File

@ -0,0 +1,809 @@
/*
* Circular Byte Buffer
* Copyright (C) 2002-2010 Stephen Ostermiller
* http://ostermiller.org/contact.pl?regarding=Java+Utilities
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* See LICENSE.txt for details.
*/
package core.util;
import java.io.*;
/**
* Implements the Circular Buffer producer/consumer model for bytes.
* More information about this class is available from <a target="_top" href=
* "http://ostermiller.org/utils/CircularByteBuffer.html">ostermiller.org</a>.
* <p>
* Using this class is a simpler alternative to using a PipedInputStream
* and a PipedOutputStream. PipedInputStreams and PipedOutputStreams don't support the
* mark operation, don't allow you to control buffer sizes that they use,
* and have a more complicated API that requires instantiating two
* classes and connecting them.
* <p>
* This class is thread safe.
*
* @see CircularCharBuffer
* @see CircularObjectBuffer
*
* @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
* @since ostermillerutils 1.00.00
*/
public class CircularByteBuffer {
/**
* The default size for a circular byte buffer.
*
* @since ostermillerutils 1.00.00
*/
private final static int DEFAULT_SIZE = 1024;
/**
* A buffer that will grow as things are added.
*
* @since ostermillerutils 1.00.00
*/
public final static int INFINITE_SIZE = -1;
/**
* The circular buffer.
* <p>
* The actual capacity of the buffer is one less than the actual length
* of the buffer so that an empty and a full buffer can be
* distinguished. An empty buffer will have the markPostion and the
* writePosition equal to each other. A full buffer will have
* the writePosition one less than the markPostion.
* <p>
* There are three important indexes into the buffer:
* The readPosition, the writePosition, and the markPosition.
* If the InputStream has never been marked, the readPosition and
* the markPosition should always be the same. The bytes
* available to be read go from the readPosition to the writePosition,
* wrapping around the end of the buffer. The space available for writing
* goes from the write position to one less than the markPosition,
* wrapping around the end of the buffer. The bytes that have
* been saved to support a reset() of the InputStream go from markPosition
* to readPosition, wrapping around the end of the buffer.
*
* @since ostermillerutils 1.00.00
*/
protected byte[] buffer;
/**
* Index of the first byte available to be read.
*
* @since ostermillerutils 1.00.00
*/
protected volatile int readPosition = 0;
/**
* Index of the first byte available to be written.
*
* @since ostermillerutils 1.00.00
*/
protected volatile int writePosition = 0;
/**
* Index of the first saved byte. (To support stream marking.)
*
* @since ostermillerutils 1.00.00
*/
protected volatile int markPosition = 0;
/**
* Number of bytes that have to be saved
* to support mark() and reset() on the InputStream.
*
* @since ostermillerutils 1.00.00
*/
protected volatile int markSize = 0;
/**
* If this buffer is infinite (should resize itself when full)
*
* @since ostermillerutils 1.00.00
*/
protected volatile boolean infinite = false;
/**
* True if a write to a full buffer should block until the buffer
* has room, false if the write method should throw an IOException
*
* @since ostermillerutils 1.00.00
*/
protected boolean blockingWrite = true;
/**
* The InputStream that can empty this buffer.
*
* @since ostermillerutils 1.00.00
*/
protected InputStream in = new CircularByteBufferInputStream();
/**
* true if the close() method has been called on the InputStream
*
* @since ostermillerutils 1.00.00
*/
protected boolean inputStreamClosed = false;
/**
* The OutputStream that can fill this buffer.
*
* @since ostermillerutils 1.00.00
*/
protected OutputStream out = new CircularByteBufferOutputStream();
/**
* true if the close() method has been called on the OutputStream
*
* @since ostermillerutils 1.00.00
*/
protected boolean outputStreamClosed = false;
/**
* Make this buffer ready for reuse. The contents of the buffer
* will be cleared and the streams associated with this buffer
* will be reopened if they had been closed.
*
* @since ostermillerutils 1.00.00
*/
public void clear(){
synchronized (this){
readPosition = 0;
writePosition = 0;
markPosition = 0;
outputStreamClosed = false;
inputStreamClosed = false;
}
}
/**
* Retrieve a OutputStream that can be used to fill
* this buffer.
* <p>
* Write methods may throw a BufferOverflowException if
* the buffer is not large enough. A large enough buffer
* size must be chosen so that this does not happen or
* the caller must be prepared to catch the exception and
* try again once part of the buffer has been consumed.
*
*
* @return the producer for this buffer.
*
* @since ostermillerutils 1.00.00
*/
public OutputStream getOutputStream(){
return out;
}
/**
* Retrieve a InputStream that can be used to empty
* this buffer.
* <p>
* This InputStream supports marks at the expense
* of the buffer size.
*
* @return the consumer for this buffer.
*
* @since ostermillerutils 1.00.00
*/
public InputStream getInputStream(){
return in;
}
/**
* Get number of bytes that are available to be read.
* <p>
* Note that the number of bytes available plus
* the number of bytes free may not add up to the
* capacity of this buffer, as the buffer may reserve some
* space for other purposes.
*
* @return the size in bytes of this buffer
*
* @since ostermillerutils 1.00.00
*/
public int getAvailable(){
synchronized (this){
return available();
}
}
/**
* Get the number of bytes this buffer has free for
* writing.
* <p>
* Note that the number of bytes available plus
* the number of bytes free may not add up to the
* capacity of this buffer, as the buffer may reserve some
* space for other purposes.
*
* @return the available space in bytes of this buffer
*
* @since ostermillerutils 1.00.00
*/
public int getSpaceLeft(){
synchronized (this){
return spaceLeft();
}
}
/**
* Get the capacity of this buffer.
* <p>
* Note that the number of bytes available plus
* the number of bytes free may not add up to the
* capacity of this buffer, as the buffer may reserve some
* space for other purposes.
*
* @return the size in bytes of this buffer
*
* @since ostermillerutils 1.00.00
*/
public int getSize(){
synchronized (this){
return buffer.length;
}
}
/**
* double the size of the buffer
*
* @since ostermillerutils 1.00.00
*/
private void resize(){
byte[] newBuffer = new byte[buffer.length * 2];
int marked = marked();
int available = available();
if (markPosition <= writePosition){
// any space between the mark and
// the first write needs to be saved.
// In this case it is all in one piece.
int length = writePosition - markPosition;
System.arraycopy(buffer, markPosition, newBuffer, 0, length);
} else {
int length1 = buffer.length - markPosition;
System.arraycopy(buffer, markPosition, newBuffer, 0, length1);
int length2 = writePosition;
System.arraycopy(buffer, 0, newBuffer, length1, length2);
}
buffer = newBuffer;
markPosition = 0;
readPosition = marked;
writePosition = marked + available;
}
/**
* Space available in the buffer which can be written.
*
* @since ostermillerutils 1.00.00
*/
private int spaceLeft(){
if (writePosition < markPosition){
// any space between the first write and
// the mark except one byte is available.
// In this case it is all in one piece.
return (markPosition - writePosition - 1);
}
// space at the beginning and end.
return ((buffer.length - 1) - (writePosition - markPosition));
}
/**
* Bytes available for reading.
*
* @since ostermillerutils 1.00.00
*/
private int available(){
if (readPosition <= writePosition){
// any space between the first read and
// the first write is available. In this case i
// is all in one piece.
return (writePosition - readPosition);
}
// space at the beginning and end.
return (buffer.length - (readPosition - writePosition));
}
/**
* Bytes saved for supporting marks.
*
* @since ostermillerutils 1.00.00
*/
private int marked(){
if (markPosition <= readPosition){
// any space between the markPosition and
// the first write is marked. In this case i
// is all in one piece.
return (readPosition - markPosition);
}
// space at the beginning and end.
return (buffer.length - (markPosition - readPosition));
}
/**
* If we have passed the markSize reset the
* mark so that the space can be used.
*
* @since ostermillerutils 1.00.00
*/
private void ensureMark(){
if (marked() > markSize){
markPosition = readPosition;
markSize = 0;
}
}
/**
* Create a new buffer with a default capacity.
* Writing to a full buffer will block until space
* is available rather than throw an exception.
*
* @since ostermillerutils 1.00.00
*/
public CircularByteBuffer(){
this (DEFAULT_SIZE, true);
}
/**
* Create a new buffer with given capacity.
* Writing to a full buffer will block until space
* is available rather than throw an exception.
* <p>
* Note that the buffer may reserve some bytes for
* special purposes and capacity number of bytes may
* not be able to be written to the buffer.
* <p>
* Note that if the buffer is of INFINITE_SIZE it will
* neither block or throw exceptions, but rather grow
* without bound.
*
* @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE.
*
* @since ostermillerutils 1.00.00
*/
public CircularByteBuffer(int size){
this (size, true);
}
/**
* Create a new buffer with a default capacity and
* given blocking behavior.
*
* @param blockingWrite true writing to a full buffer should block
* until space is available, false if an exception should
* be thrown instead.
*
* @since ostermillerutils 1.00.00
*/
public CircularByteBuffer(boolean blockingWrite){
this (DEFAULT_SIZE, blockingWrite);
}
/**
* Create a new buffer with the given capacity and
* blocking behavior.
* <p>
* Note that the buffer may reserve some bytes for
* special purposes and capacity number of bytes may
* not be able to be written to the buffer.
* <p>
* Note that if the buffer is of INFINITE_SIZE it will
* neither block or throw exceptions, but rather grow
* without bound.
*
* @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE.
* @param blockingWrite true writing to a full buffer should block
* until space is available, false if an exception should
* be thrown instead.
*
* @since ostermillerutils 1.00.00
*/
public CircularByteBuffer(int size, boolean blockingWrite){
if (size == INFINITE_SIZE){
buffer = new byte[DEFAULT_SIZE];
infinite = true;
} else {
buffer = new byte[size];
infinite = false;
}
this.blockingWrite = blockingWrite;
}
/**
* Class for reading from a circular byte buffer.
*
* @since ostermillerutils 1.00.00
*/
protected class CircularByteBufferInputStream extends InputStream {
/**
* Returns the number of bytes that can be read (or skipped over) from this
* input stream without blocking by the next caller of a method for this input
* stream. The next caller might be the same thread or or another thread.
*
* @return the number of bytes that can be read from this input stream without blocking.
* @throws IOException if the stream is closed.
*
* @since ostermillerutils 1.00.00
*/
@Override public int available() throws IOException {
synchronized (CircularByteBuffer.this){
if (inputStreamClosed) throw new IOException("InputStream has been closed, it is not ready.");
return (CircularByteBuffer.this.available());
}
}
/**
* Close the stream. Once a stream has been closed, further read(), available(),
* mark(), or reset() invocations will throw an IOException. Closing a
* previously-closed stream, however, has no effect.
*
* @throws IOException never.
*
* @since ostermillerutils 1.00.00
*/
@Override public void close() throws IOException {
synchronized (CircularByteBuffer.this){
inputStreamClosed = true;
}
}
/**
* Mark the present position in the stream. Subsequent calls to reset() will
* attempt to reposition the stream to this point.
* <p>
* The readAheadLimit must be less than the size of circular buffer, otherwise
* this method has no effect.
*
* @param readAheadLimit Limit on the number of bytes that may be read while
* still preserving the mark. After reading this many bytes, attempting to
* reset the stream will fail.
*
* @since ostermillerutils 1.00.00
*/
@Override public void mark(int readAheadLimit) {
synchronized (CircularByteBuffer.this){
//if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot mark a closed InputStream.");
if (buffer.length - 1 > readAheadLimit) {
markSize = readAheadLimit;
markPosition = readPosition;
}
}
}
/**
* Tell whether this stream supports the mark() operation.
*
* @return true, mark is supported.
*
* @since ostermillerutils 1.00.00
*/
@Override public boolean markSupported() {
return true;
}
/**
* Read a single byte.
* This method will block until a byte is available, an I/O error occurs,
* or the end of the stream is reached.
*
* @return The byte read, as an integer in the range 0 to 255 (0x00-0xff),
* or -1 if the end of the stream has been reached
* @throws IOException if the stream is closed.
*
* @since ostermillerutils 1.00.00
*/
@Override public int read() throws IOException {
while (true){
synchronized (CircularByteBuffer.this){
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream.");
int available = CircularByteBuffer.this.available();
if (available > 0){
int result = buffer[readPosition] & 0xff;
readPosition++;
if (readPosition == buffer.length){
readPosition = 0;
}
ensureMark();
return result;
} else if (outputStreamClosed){
return -1;
}
}
try {
Thread.sleep(100);
} catch(Exception x){
throw new IOException("Blocking read operation interrupted.");
}
}
}
/**
* Read bytes into an array.
* This method will block until some input is available,
* an I/O error occurs, or the end of the stream is reached.
*
* @param cbuf Destination buffer.
* @return The number of bytes read, or -1 if the end of
* the stream has been reached
* @throws IOException if the stream is closed.
*
* @since ostermillerutils 1.00.00
*/
@Override public int read(byte[] cbuf) throws IOException {
return read(cbuf, 0, cbuf.length);
}
/**
* Read bytes into a portion of an array.
* This method will block until some input is available,
* an I/O error occurs, or the end of the stream is reached.
*
* @param cbuf Destination buffer.
* @param off Offset at which to start storing bytes.
* @param len Maximum number of bytes to read.
* @return The number of bytes read, or -1 if the end of
* the stream has been reached
* @throws IOException if the stream is closed.
*
* @since ostermillerutils 1.00.00
*/
@Override public int read(byte[] cbuf, int off, int len) throws IOException {
while (true){
synchronized (CircularByteBuffer.this){
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream.");
int available = CircularByteBuffer.this.available();
if (available > 0){
int length = Math.min(len, available);
int firstLen = Math.min(length, buffer.length - readPosition);
int secondLen = length - firstLen;
System.arraycopy(buffer, readPosition, cbuf, off, firstLen);
if (secondLen > 0){
System.arraycopy(buffer, 0, cbuf, off+firstLen, secondLen);
readPosition = secondLen;
} else {
readPosition += length;
}
if (readPosition == buffer.length) {
readPosition = 0;
}
ensureMark();
return length;
} else if (outputStreamClosed){
return -1;
}
}
try {
Thread.sleep(100);
} catch(Exception x){
throw new IOException("Blocking read operation interrupted.");
}
}
}
/**
* Reset the stream.
* If the stream has been marked, then attempt to reposition i
* at the mark. If the stream has not been marked, or more bytes
* than the readAheadLimit have been read, this method has no effect.
*
* @throws IOException if the stream is closed.
*
* @since ostermillerutils 1.00.00
*/
@Override public void reset() throws IOException {
synchronized (CircularByteBuffer.this){
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot reset a closed InputStream.");
readPosition = markPosition;
}
}
/**
* Skip bytes.
* This method will block until some bytes are available,
* an I/O error occurs, or the end of the stream is reached.
*
* @param n The number of bytes to skip
* @return The number of bytes actually skipped
* @throws IllegalArgumentException if n is negative.
* @throws IOException if the stream is closed.
*
* @since ostermillerutils 1.00.00
*/
@Override public long skip(long n) throws IOException, IllegalArgumentException {
while (true){
synchronized (CircularByteBuffer.this){
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot skip bytes on a closed InputStream.");
int available = CircularByteBuffer.this.available();
if (available > 0){
int length = Math.min((int)n, available);
int firstLen = Math.min(length, buffer.length - readPosition);
int secondLen = length - firstLen;
if (secondLen > 0){
readPosition = secondLen;
} else {
readPosition += length;
}
if (readPosition == buffer.length) {
readPosition = 0;
}
ensureMark();
return length;
} else if (outputStreamClosed){
return 0;
}
}
try {
Thread.sleep(100);
} catch(Exception x){
throw new IOException("Blocking read operation interrupted.");
}
}
}
}
/**
* Class for writing to a circular byte buffer.
* If the buffer is full, the writes will either block
* until there is some space available or throw an IOException
* based on the CircularByteBuffer's preference.
*
* @since ostermillerutils 1.00.00
*/
protected class CircularByteBufferOutputStream extends OutputStream {
/**
* Close the stream, flushing it first.
* This will cause the InputStream associated with this circular buffer
* to read its last bytes once it empties the buffer.
* Once a stream has been closed, further write() or flush() invocations
* will cause an IOException to be thrown. Closing a previously-closed stream,
* however, has no effect.
*
* @throws IOException never.
*
* @since ostermillerutils 1.00.00
*/
@Override public void close() throws IOException {
synchronized (CircularByteBuffer.this){
if (!outputStreamClosed){
flush();
}
outputStreamClosed = true;
}
}
/**
* Flush the stream.
*
* @throws IOException if the stream is closed.
*
* @since ostermillerutils 1.00.00
*/
@Override public void flush() throws IOException {
synchronized (CircularByteBuffer.this){
if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot flush a closed OutputStream.");
if (inputStreamClosed) throw new IOException("Buffer closed by inputStream; cannot flush.");
}
// this method needs to do nothing
}
/**
* Write an array of bytes.
* If the buffer allows blocking writes, this method will block until
* all the data has been written rather than throw an IOException.
*
* @param cbuf Array of bytes to be written
* @throws BufferOverflowException if buffer does not allow blocking writes
* and the buffer is full. If the exception is thrown, no data
* will have been written since the buffer was set to be non-blocking.
* @throws IOException if the stream is closed, or the write is interrupted.
*
* @since ostermillerutils 1.00.00
*/
@Override public void write(byte[] cbuf) throws IOException {
write(cbuf, 0, cbuf.length);
}
/**
* Write a portion of an array of bytes.
* If the buffer allows blocking writes, this method will block until
* all the data has been written rather than throw an IOException.
*
* @param cbuf Array of bytes
* @param off Offset from which to start writing bytes
* @param len - Number of bytes to write
* @throws BufferOverflowException if buffer does not allow blocking writes
* and the buffer is full. If the exception is thrown, no data
* will have been written since the buffer was set to be non-blocking.
* @throws IOException if the stream is closed, or the write is interrupted.
*
* @since ostermillerutils 1.00.00
*/
@Override public void write(byte[] cbuf, int off, int len) throws IOException {
while (len > 0){
synchronized (CircularByteBuffer.this){
if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream.");
if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer.");
int spaceLeft = spaceLeft();
while (infinite && spaceLeft < len){
resize();
spaceLeft = spaceLeft();
}
if (!blockingWrite && spaceLeft < len) throw new IOException("CircularByteBuffer is full; cannot write " + len + " bytes");
int realLen = Math.min(len, spaceLeft);
int firstLen = Math.min(realLen, buffer.length - writePosition);
int secondLen = Math.min(realLen - firstLen, buffer.length - markPosition - 1);
int written = firstLen + secondLen;
if (firstLen > 0){
System.arraycopy(cbuf, off, buffer, writePosition, firstLen);
}
if (secondLen > 0){
System.arraycopy(cbuf, off+firstLen, buffer, 0, secondLen);
writePosition = secondLen;
} else {
writePosition += written;
}
if (writePosition == buffer.length) {
writePosition = 0;
}
off += written;
len -= written;
}
if (len > 0){
try {
Thread.sleep(100);
} catch(Exception x){
throw new IOException("Waiting for available space in buffer interrupted.");
}
}
}
}
/**
* Write a single byte.
* The byte to be written is contained in the 8 low-order bits of the
* given integer value; the 24 high-order bits are ignored.
* If the buffer allows blocking writes, this method will block until
* all the data has been written rather than throw an IOException.
*
* @param c number of bytes to be written
* @throws BufferOverflowException if buffer does not allow blocking writes
* and the buffer is full.
* @throws IOException if the stream is closed, or the write is interrupted.
*
* @since ostermillerutils 1.00.00
*/
@Override public void write(int c) throws IOException {
boolean written = false;
while (!written){
synchronized (CircularByteBuffer.this){
if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream.");
if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer.");
int spaceLeft = spaceLeft();
while (infinite && spaceLeft < 1){
resize();
spaceLeft = spaceLeft();
}
if (!blockingWrite && spaceLeft < 1) throw new IOException("CircularByteBuffer is full; cannot write 1 byte");
if (spaceLeft > 0){
buffer[writePosition] = (byte)(c & 0xff);
writePosition++;
if (writePosition == buffer.length) {
writePosition = 0;
}
written = true;
}
}
if (!written){
try {
Thread.sleep(100);
} catch(Exception x){
throw new IOException("Waiting for available space in buffer interrupted.");
}
}
}
}
}
}

View File

@ -0,0 +1,98 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Collectionz
{
public static <T> List<T> toMutableList(T[] a)
{
ArrayList<T> l = new ArrayList<T>();
for (T t : a)
l.add(t);
return l;
}
public static <T> Collection<T> filterNull (Collection<T> items)
{
List<T> l = new ArrayList<T>();
for (T i : items)
if (i != null)
l.add(i);
return l;
}
public static <T> Collection<T> filterNull (T... items)
{
List<T> l = new ArrayList<T>();
for (T i : items)
if (i != null)
l.add(i);
return l;
}
static public void removeByFirst (Collection<? extends Pair> items, Object remove)
{
Object found = null;
for (Pair x : items)
{
if (x.first.equals(remove))
{
found = x;
break;
}
}
if (found != null)
items.remove(found);
}
static public void removeBySecond (Collection<? extends Pair> items, Object remove)
{
Object found = null;
for (Pair x : items)
{
if (x.second.equals(remove))
{
found = x;
break;
}
}
if (found != null)
items.remove(found);
}
static public boolean containsByFirst (Collection<? extends Pair> items, Object remove)
{
for (Pair x : items)
{
if (x.first.equals(remove))
return true;
}
return false;
}
static public boolean containsBySecond (Collection<? extends Pair> items, Object remove)
{
for (Pair x : items)
{
if (x.second.equals(remove))
return true;
}
return false;
}
}

View File

@ -0,0 +1,96 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import java.util.Comparator;
public class Comparators
{
public static class SortBySecond<S> implements Comparator<Pair<?,S>>
{
Comparator<S> c;
public SortBySecond(Comparator<S> c)
{
this.c = c;
}
@Override
public int compare(Pair<?,S> p1, Pair<?,S> p2)
{
return c.compare(p1.second, p2.second);
}
}
public static class SortByFirst<S> implements Comparator<Pair<S,?>>
{
Comparator<S> c;
public SortByFirst(Comparator<S> c)
{
this.c = c;
}
@Override
public int compare(Pair<S,?> p1, Pair<S,?> p2)
{
return c.compare(p1.first, p2.first);
}
}
public static class SortByFirstReverse<S> implements Comparator<Pair<S,?>>
{
Comparator<S> c;
public SortByFirstReverse(Comparator<S> c)
{
this.c = c;
}
@Override
public int compare(Pair<S,?> p1, Pair<S,?> p2)
{
return c.compare(p2.first, p1.first);
}
}
public static class SortBySecondNatural<S extends Comparable<S>> implements Comparator<Pair<?,S>>
{
@Override
public int compare(Pair<?, S> o1, Pair<?, S> o2)
{
return o1.second.compareTo(o2.second);
}
}
public static class SortByFirstNatural<S extends Comparable<S>> implements Comparator<Pair<S,?>>
{
@Override
public int compare(Pair<S,?> o1, Pair<S,?> o2)
{
return o1.first.compareTo(o2.first);
}
}
public static class SortBySecondNaturalOpposite<S extends Comparable<S>> implements Comparator<Pair<?,S>>
{
@Override
public int compare(Pair<?, S> o1, Pair<?, S> o2)
{
return o2.second.compareTo(o1.second);
}
}
public static class SortByFirstNaturalOpposite<S extends Comparable<S>> implements Comparator<Pair<S,?>>
{
@Override
public int compare(Pair<S,?> o1, Pair<S,?> o2)
{
return o2.first.compareTo(o1.first);
}
}
}

View File

@ -0,0 +1,38 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class DateFormat
{
SimpleDateFormat sdf;
public DateFormat(String format)
{
sdf = new SimpleDateFormat(format);
}
public String format(Date date, int i)
{
sdf.setTimeZone(TimeZone.getTimeZone("GMT-"+i+":00"));
return sdf.format(date);
}
public String format(Date date)
{
return format(date, 0);
}
public Date parse(String time) throws ParseException
{
return sdf.parse(time);
}
}

View File

@ -0,0 +1,111 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import core.connector.FileInfo;
//import core.connector.sync.StoreConnector;
public class Environment extends HashMap<String,String>
{
private static final long serialVersionUID = 1L;
public Environment ()
{
}
/*
public static Environment fromStore (StoreConnector connector) throws Exception
{
Environment e = new Environment ();
connector.open();
e.readFromStore(connector);
connector.close();
return e;
}
public void readFromStore (StoreConnector connector) throws Exception
{
List<FileInfo> files = connector.listDirectory("");
for (FileInfo file : files)
{
put(file.relativePath, new String(connector.get(file.relativePath), "UTF-8"));
}
}
public static void toStore (StoreConnector connector, Environment e) throws Exception
{
connector.open();
e.writeToStore(connector);
connector.close();
}
public void writeToStore (StoreConnector connector) throws Exception
{
for (String key : keySet())
connector.put(key, Strings.toBytes(this.get(key)));
}
*/
public String checkGet (String key)
{
// find a better exception
if (!containsKey(key))
throw new NullPointerException("Unknown key: " + key);
return get(key);
}
public Environment childEnvironment (String key)
{
Environment e = new Environment();
String prefix = key + "/";
int prefixLength = prefix.length();
for (Map.Entry<String, String> i : entrySet())
{
String k = i.getKey();
if (k.startsWith(prefix))
{
e.put(k.substring(prefixLength), i.getValue());
}
}
return e;
}
public void addChildEnvironment (String key, Environment e)
{
String prefix = key + "/";
for (Map.Entry<String, String> i : e.entrySet())
{
String k = i.getKey();
this.put(prefix + k, i.getValue());
}
}
public boolean hasChildEnvironment (String key)
{
String prefix = key + "/";
int prefixLength = prefix.length();
for (Map.Entry<String, String> i : entrySet())
{
String k = i.getKey();
if (k.startsWith(prefix))
{
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,11 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
public interface ExceptionHandler
{
public void exception (Object ... arguments);
}

View File

@ -0,0 +1,39 @@
/**
* Author: Timothy Prepscius
* License: GPLv3 Affero + keep my name in the code!
*/
package core.util;
import java.io.FileInputStream;
import java.io.InputStream;
public class ExternalResource
{
static LogOut log = new LogOut(ExternalResource.class);
static protected String prefix;
static {
prefix = System.getProperty("user.home") + "/resources/";
}
public static byte[] get(String key) throws Exception
{
String path = prefix + key;
log.debug("get", path);
return Streams.readFullyBytes(new FileInputStream(path));
}
public static InputStream getResourceAsStream(Class<?> c, String key) throws Exception
{
String path = prefix + c.getPackage().getName() + "/" + key;
log.debug("getResourceAsStream", path);
return new FileInputStream(path);
}
public static String getTrimmedString(String key) throws Exception
{
return Strings.toString(get(key)).trim();
}
}

Some files were not shown because too many files have changed in this diff Show More