Implemented counting AES-GCM IV
This commit is contained in:
parent
dda6086a2c
commit
a82dbf81b5
|
@ -49,6 +49,7 @@ class MetaChannel {
|
|||
|
||||
public AsymmetricCipherKeyPair ecdhKey; // used for ECC Diffie-Hellman-Merkle key exchanges: see http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
|
||||
|
||||
// since we are using AES-GCM, the aesIV here **MUST** be exactly 12 bytes
|
||||
public byte[] aesKey;
|
||||
public byte[] aesIV;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package dorkbox.network.connection.registration.remote;
|
||||
|
||||
import com.esotericsoftware.kryo.io.Input;
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.ConnectionImpl;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
|
@ -28,6 +29,7 @@ import dorkbox.network.pipeline.udp.KryoEncoderUdpCrypto;
|
|||
import dorkbox.network.util.CryptoSerializationManager;
|
||||
import dorkbox.util.collections.IntMap;
|
||||
import dorkbox.util.collections.IntMap.Entries;
|
||||
import dorkbox.util.serialization.EccPublicKeySerializer;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
|
@ -37,8 +39,11 @@ import io.netty.channel.socket.nio.NioDatagramChannel;
|
|||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.channel.udt.nio.NioUdtByteConnectorChannel;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import org.bouncycastle.crypto.engines.AESFastEngine;
|
||||
import org.bouncycastle.crypto.modes.GCMBlockCipher;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -295,6 +300,59 @@ class RegistrationRemoteHandler<C extends Connection> extends RegistrationHandle
|
|||
}
|
||||
}
|
||||
|
||||
protected final
|
||||
ECPublicKeyParameters verifyPayload(final Object message,
|
||||
final Channel channel,
|
||||
final RegistrationWrapper registrationWrapper,
|
||||
final Logger logger,
|
||||
final byte[] payload) {
|
||||
|
||||
if (payload.length == 0) {
|
||||
logger.error("Invalid decryption of payload. Aborting.");
|
||||
shutdown(registrationWrapper, channel);
|
||||
|
||||
ReferenceCountUtil.release(message);
|
||||
return null;
|
||||
}
|
||||
|
||||
ECPublicKeyParameters ecdhPubKey = EccPublicKeySerializer.read(new Input(payload));
|
||||
|
||||
if (ecdhPubKey == null) {
|
||||
logger.error("Invalid decode of ecdh public key. Aborting.");
|
||||
shutdown(registrationWrapper, channel);
|
||||
|
||||
ReferenceCountUtil.release(message);
|
||||
return null;
|
||||
}
|
||||
return ecdhPubKey;
|
||||
}
|
||||
|
||||
protected final
|
||||
boolean verifyAesInfo(final Object message,
|
||||
final Channel channel,
|
||||
final RegistrationWrapper registrationWrapper,
|
||||
final MetaChannel metaChannel,
|
||||
final Logger logger) {
|
||||
|
||||
if (metaChannel.aesKey.length != 32) {
|
||||
logger.error("Fatal error trying to use AES key (wrong key length).");
|
||||
shutdown(registrationWrapper, channel);
|
||||
|
||||
ReferenceCountUtil.release(message);
|
||||
return true;
|
||||
}
|
||||
// IV length must == 12 because we are using GCM!
|
||||
else if (metaChannel.aesIV.length != 12) {
|
||||
logger.error("Fatal error trying to use AES IV (wrong IV length).");
|
||||
shutdown(registrationWrapper, channel);
|
||||
|
||||
ReferenceCountUtil.release(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// have to setup AFTER establish connection, data, as we don't want to enable AES until we're ready.
|
||||
@SuppressWarnings("AutoUnboxing")
|
||||
protected final
|
||||
|
|
|
@ -160,7 +160,7 @@ class RegistrationRemoteHandlerClientTCP<C extends Connection> extends Registrat
|
|||
channel.writeAndFlush(registration);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"AutoUnboxing", "AutoBoxing"})
|
||||
@SuppressWarnings({"AutoUnboxing", "AutoBoxing", "Duplicates"})
|
||||
@Override
|
||||
public
|
||||
void channelRead(final ChannelHandlerContext context, final Object message) throws Exception {
|
||||
|
@ -252,7 +252,6 @@ class RegistrationRemoteHandlerClientTCP<C extends Connection> extends Registrat
|
|||
*/
|
||||
byte[] ecdhPubKeyBytes = Arrays.copyOfRange(payload, intLength, payload.length);
|
||||
ECPublicKeyParameters ecdhPubKey = EccPublicKeySerializer.read(new Input(ecdhPubKeyBytes));
|
||||
|
||||
if (ecdhPubKey == null) {
|
||||
logger2.error("Invalid decode of ecdh public key. Aborting.");
|
||||
shutdown(registrationWrapper2, channel);
|
||||
|
@ -290,18 +289,13 @@ class RegistrationRemoteHandlerClientTCP<C extends Connection> extends Registrat
|
|||
sha384.doFinal(digest, 0);
|
||||
|
||||
metaChannel.aesKey = Arrays.copyOfRange(digest, 0, 32); // 256bit keysize (32 bytes)
|
||||
metaChannel.aesIV = Arrays.copyOfRange(digest, 32, 48); // 128bit blocksize (16 bytes)
|
||||
metaChannel.aesIV = Arrays.copyOfRange(digest, 32, 44); // 96bit blocksize (12 bytes) required by AES-GCM
|
||||
|
||||
// abort if something messed up!
|
||||
if (metaChannel.aesKey.length != 32) {
|
||||
logger2.error("Fatal error trying to use AES key (wrong key length).");
|
||||
shutdown(registrationWrapper2, channel);
|
||||
|
||||
ReferenceCountUtil.release(message);
|
||||
if (verifyAesInfo(message, channel, registrationWrapper2, metaChannel, logger2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Registration register = new Registration();
|
||||
|
||||
// encrypt the ECDH public key using our previous AES info
|
||||
|
|
|
@ -55,7 +55,7 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
private static final ECParameterSpec eccSpec = ECNamedCurveTable.getParameterSpec(CryptoECC.p521_curve);
|
||||
private final Object ecdhKeyLock = new Object();
|
||||
private final ThreadLocal<IESEngine> eccEngineLocal = new ThreadLocal<IESEngine>();
|
||||
private AsymmetricCipherKeyPair ecdhKeyPair = CryptoECC.generateKeyPair(eccSpec, new SecureRandom());
|
||||
private AsymmetricCipherKeyPair ecdhKeyPair;
|
||||
private volatile long ecdhTimeout = System.nanoTime();
|
||||
|
||||
|
||||
|
@ -81,7 +81,7 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
*/
|
||||
private
|
||||
AsymmetricCipherKeyPair getEchdKeyOnRotate(final SecureRandom secureRandom) {
|
||||
if (System.nanoTime() - this.ecdhTimeout > ECDH_TIMEOUT) {
|
||||
if (this.ecdhKeyPair == null || System.nanoTime() - this.ecdhTimeout > ECDH_TIMEOUT) {
|
||||
synchronized (this.ecdhKeyLock) {
|
||||
this.ecdhTimeout = System.nanoTime();
|
||||
this.ecdhKeyPair = CryptoECC.generateKeyPair(eccSpec, secureRandom);
|
||||
|
@ -132,6 +132,7 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
/**
|
||||
* STEP 3-XXXXX: We pass registration messages around until we the registration handshake is complete!
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
public
|
||||
void channelRead(ChannelHandlerContext context, Object message) throws Exception {
|
||||
|
@ -232,7 +233,7 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
|
||||
// now we have to setup the TEMP AES key!
|
||||
metaChannel.aesKey = new byte[32]; // 256bit keysize (32 bytes)
|
||||
metaChannel.aesIV = new byte[16]; // 128bit blocksize (16 bytes)
|
||||
metaChannel.aesIV = new byte[12]; // 96bit blocksize (12 bytes) required by AES-GCM
|
||||
secureRandom.nextBytes(metaChannel.aesKey);
|
||||
secureRandom.nextBytes(metaChannel.aesIV);
|
||||
|
||||
|
@ -282,6 +283,7 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
registration.payload,
|
||||
logger);
|
||||
|
||||
// abort if we cannot properly get the key info from the payload
|
||||
if (payload.length == 0) {
|
||||
logger2.error("Invalid decryption of payload. Aborting.");
|
||||
shutdown(registrationWrapper2, channel);
|
||||
|
@ -290,8 +292,11 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Diffie-Hellman-Merkle key exchange for the AES key
|
||||
* see http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
|
||||
*/
|
||||
ECPublicKeyParameters ecdhPubKey = EccPublicKeySerializer.read(new Input(payload));
|
||||
|
||||
if (ecdhPubKey == null) {
|
||||
logger2.error("Invalid decode of ecdh public key. Aborting.");
|
||||
shutdown(registrationWrapper2, channel);
|
||||
|
@ -319,7 +324,12 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
sha384.doFinal(digest, 0);
|
||||
|
||||
metaChannel.aesKey = Arrays.copyOfRange(digest, 0, 32); // 256bit keysize (32 bytes)
|
||||
metaChannel.aesIV = Arrays.copyOfRange(digest, 32, 48); // 128bit blocksize (16 bytes)
|
||||
metaChannel.aesIV = Arrays.copyOfRange(digest, 32, 44); // 96bit blocksize (12 bytes) required by AES-GCM
|
||||
|
||||
// abort if something messed up!
|
||||
if (verifyAesInfo(message, channel, registrationWrapper2, metaChannel, logger2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// tell the client to continue it's registration process.
|
||||
channel.writeAndFlush(new Registration());
|
||||
|
@ -330,7 +340,7 @@ class RegistrationRemoteHandlerServerTCP<C extends Connection> extends Registrat
|
|||
channel.writeAndFlush(registration); // causes client to setup network connection & AES
|
||||
|
||||
setupConnectionCrypto(metaChannel);
|
||||
// AES ENCRPYTION NOW USED
|
||||
// AES ENCRYPTION NOW USED
|
||||
|
||||
// this sets up the pipeline for the server, so all the necessary handlers are ready to go
|
||||
establishConnection(metaChannel);
|
||||
|
|
Loading…
Reference in New Issue
Block a user