Overgram/lib/src/main/java/io/github/lonamiwebs/overgram/utils/Utils.java

147 lines
4.8 KiB
Java

package io.github.lonamiwebs.overgram.utils;
import javafx.util.Pair;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
public class Utils {
private static MessageDigest sha1;
private static SecureRandom random;
static {
random = new SecureRandom();
try {
sha1 = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException ignored) {
}
}
public static BigInteger randomBigInteger(final BigInteger max) {
BigInteger result;
do {
result = new BigInteger(max.bitLength(), random);
} while (result.compareTo(max) >= 0);
return result;
}
public static byte[] randomBytes(final int size) {
final byte[] result = new byte[size];
random.nextBytes(result);
return result;
}
// Note that this reverses IN PLACE and returns the same pointer
public static byte[] reversed(final byte[] bytes) {
for (int i = bytes.length / 2; i-- != 0; ) {
final byte temp = bytes[i];
bytes[i] = bytes[bytes.length - i - 1];
bytes[bytes.length - i - 1] = temp;
}
return bytes;
}
public static byte[] concat(final byte[] left, final byte[] right, final int rightLength) {
final byte[] result = Arrays.copyOf(left, left.length + rightLength);
System.arraycopy(right, 0, result, left.length, rightLength);
return result;
}
public static byte[] concat(final byte[] left, final byte[] right) {
return concat(left, right, right.length);
}
public static Pair<BigInteger, BigInteger> factorize(final BigInteger pq) {
final BigInteger two = new BigInteger("2");
if (pq.mod(two).equals(BigInteger.ZERO)) {
return new Pair<>(two, pq.divide(two));
}
BigInteger y = BigInteger.ONE.add(randomBigInteger(pq.subtract(two)));
BigInteger c = BigInteger.ONE.add(randomBigInteger(pq.subtract(two)));
BigInteger m = BigInteger.ONE.add(randomBigInteger(pq.subtract(two)));
BigInteger g = BigInteger.ONE;
BigInteger r = BigInteger.ONE;
BigInteger q = BigInteger.ONE;
BigInteger x = BigInteger.ZERO;
BigInteger ys = BigInteger.ZERO;
BigInteger countDown;
while (g.equals(BigInteger.ONE)) {
x = y;
countDown = r;
while (!countDown.equals(BigInteger.ZERO)) {
countDown = countDown.subtract(BigInteger.ONE);
y = (y.modPow(two, pq).add(c)).mod(pq);
}
BigInteger k = BigInteger.ZERO;
while (k.compareTo(r) < 0 && g.equals(BigInteger.ONE)) {
ys = y;
countDown = m.min(r.subtract(k));
while (!countDown.equals(BigInteger.ZERO)) {
countDown = countDown.subtract(BigInteger.ONE);
y = y.modPow(two, pq).add(c).mod(pq);
q = q.multiply(x.subtract(y).abs()).mod(pq);
}
g = q.gcd(pq);
k = k.add(m);
}
r = r.multiply(two);
}
if (g.equals(pq)) {
do {
ys = ys.modPow(two, pq).add(c).mod(pq);
g = x.subtract(ys).abs().gcd(pq);
} while (g.compareTo(BigInteger.ONE) <= 0);
}
x = g;
y = pq.divide(g);
return new Pair<>(x.min(y), x.max(y));
}
public static byte[] sha1digest(final byte[] data) throws SecurityException {
if (sha1 == null) {
throw new SecurityException("SHA-1 is required but not available");
}
final byte[] result = sha1.digest(data);
sha1.reset();
return result;
}
public static Pair<byte[], byte[]> generateKeyDataFromNonce(BigInteger serverNonce, BigInteger newNonce) {
final byte[] serverNonceBytes = reversed(serverNonce.toByteArray());
final byte[] newNonceBytes = reversed(newNonce.toByteArray());
final byte[] hash1 = sha1digest(concat(newNonceBytes, serverNonceBytes));
final byte[] hash2 = sha1digest(concat(serverNonceBytes, newNonceBytes));
final byte[] hash3 = sha1digest(concat(newNonceBytes, newNonceBytes));
final byte[] key = concat(hash1, hash2, 12);
final byte[] iv = new byte[8];
System.arraycopy(hash2, 12, iv, 0, 8);
return new Pair<>(key, concat(iv, concat(hash3, newNonceBytes, 4)));
}
public static byte[] xor(final byte[] a, final byte[] b) {
final byte[] result = new byte[Math.min(a.length, b.length)];
for (int i = 0; i < result.length; ++i) {
result[i] = (byte) (0xff & (a[i] ^ b[i]));
}
return result;
}
}