83 lines
3.1 KiB
Java
83 lines
3.1 KiB
Java
package io.github.lonamiwebs.overgram.crypto;
|
|
|
|
import io.github.lonamiwebs.overgram.network.MTProtoPlainSender;
|
|
import io.github.lonamiwebs.overgram.tl.Abstract;
|
|
import io.github.lonamiwebs.overgram.tl.Functions;
|
|
import io.github.lonamiwebs.overgram.tl.Types;
|
|
import io.github.lonamiwebs.overgram.utils.RSA;
|
|
import io.github.lonamiwebs.overgram.utils.Utils;
|
|
import javafx.util.Pair;
|
|
|
|
import java.io.IOException;
|
|
import java.math.BigInteger;
|
|
|
|
public class Authenticator {
|
|
|
|
public static void doAuthentication(final MTProtoPlainSender sender) throws IOException, ClassNotFoundException {
|
|
final BigInteger nonce = new BigInteger(Utils.randomBytes(16));
|
|
final Types.ResPQ resPq = sender.send(
|
|
new Functions.ReqPqMulti().nonce(nonce));
|
|
|
|
if (!resPq.nonce().equals(nonce)) {
|
|
throw new SecurityException("Step 1 response nonce invalid");
|
|
}
|
|
|
|
// Note that Java uses big endian, which is correct here
|
|
final BigInteger pq = new BigInteger(resPq.pq());
|
|
final Pair<BigInteger, BigInteger> pqPair = Utils.factorize(pq);
|
|
final BigInteger p = pqPair.getKey();
|
|
final BigInteger q = pqPair.getValue();
|
|
|
|
// Once again, as big endian
|
|
final byte[] pBytes = p.toByteArray();
|
|
final byte[] qBytes = q.toByteArray();
|
|
|
|
final BigInteger newNonce = new BigInteger(Utils.randomBytes(32));
|
|
final byte[] pqInnerData = new Types.PQInnerData()
|
|
.pq(resPq.pq())
|
|
.p(pBytes)
|
|
.q(qBytes)
|
|
.nonce(resPq.nonce())
|
|
.serverNonce(resPq.serverNonce())
|
|
.newNonce(newNonce)
|
|
.serializeToBytes();
|
|
|
|
byte[] cipherText = null;
|
|
long targetFingerprint = 0;
|
|
for (final long fingerprint : resPq.serverPublicKeyFingerprints()) {
|
|
cipherText = RSA.encrypt(fingerprint, pqInnerData);
|
|
if (cipherText != null) {
|
|
targetFingerprint = fingerprint;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cipherText == null) {
|
|
throw new SecurityException("Step 2 could not find a known RSA key");
|
|
}
|
|
|
|
final Abstract.ServerDHParams abstractDhParams = sender.send(
|
|
new Functions.ReqDHParams()
|
|
.nonce(resPq.nonce())
|
|
.serverNonce(resPq.serverNonce())
|
|
.p(pBytes)
|
|
.q(qBytes)
|
|
.publicKeyFingerprint(targetFingerprint)
|
|
.encryptedData(cipherText)
|
|
);
|
|
|
|
if (abstractDhParams instanceof Types.ServerDHParamsFail) {
|
|
// We could also check its nonce etc. but not needed
|
|
throw new SecurityException("Step 2 generation of DH params failed");
|
|
}
|
|
|
|
final Types.ServerDHParamsOk dhParams = (Types.ServerDHParamsOk) abstractDhParams;
|
|
if (!dhParams.nonce().equals(resPq.nonce())) {
|
|
throw new SecurityException("Step 2 DH params have invalid nonce");
|
|
}
|
|
if (!dhParams.serverNonce().equals(resPq.serverNonce())) {
|
|
throw new SecurityException("Step 2 DH params have invalid nonce");
|
|
}
|
|
}
|
|
}
|