public Packet Auth(PublicKey remoteNodeId, EncryptionHandshake handshake) { handshake.RemoteNodeId = remoteNodeId; handshake.InitiatorNonce = _cryptoRandom.GenerateRandomBytes(32); handshake.EphemeralPrivateKey = _ephemeralGenerator.Generate(); byte[] staticSharedSecret = Proxy.EcdhSerialized(remoteNodeId.Bytes, _privateKey.KeyBytes); byte[] forSigning = staticSharedSecret.Xor(handshake.InitiatorNonce); AuthEip8Message authMessage = new AuthEip8Message(); authMessage.Nonce = handshake.InitiatorNonce; authMessage.PublicKey = _privateKey.PublicKey; authMessage.Signature = _ecdsa.Sign(handshake.EphemeralPrivateKey, new Keccak(forSigning)); byte[] authData = _messageSerializationService.Serialize(authMessage); int size = authData.Length + 32 + 16 + 65; // data + MAC + IV + pub byte[] sizeBytes = size.ToBigEndianByteArray().Slice(2, 2); byte[] packetData = _eciesCipher.Encrypt( remoteNodeId, authData, sizeBytes); handshake.AuthPacket = new Packet(Bytes.Concat(sizeBytes, packetData)); return(handshake.AuthPacket); }
public void Agree(EncryptionHandshake handshake, Packet ack) { handshake.AckPacket = ack; try { byte[] plaintextOld = _eciesCipher.Decrypt(_privateKey, ack.Data); AckMessage ackMessage = _messageSerializationService.Deserialize <AckMessage>(plaintextOld); _logger.Debug($"Received ACK old"); handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey; handshake.RecipientNonce = ackMessage.Nonce; } catch (Exception) { byte[] sizeData = ack.Data.Slice(0, 2); byte[] plaintext = _eciesCipher.Decrypt(_privateKey, ack.Data.Slice(2), sizeData); AckEip8Message ackMessage = _messageSerializationService.Deserialize <AckEip8Message>(plaintext); _logger.Debug($"Received ACK v{ackMessage.Version}"); handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey; handshake.RecipientNonce = ackMessage.Nonce; } SetSecrets(handshake, EncryptionHandshakeRole.Initiator); }
private void SetSecrets(EncryptionHandshake handshake, HandshakeRole handshakeRole) { byte[] ephemeralSharedSecret = Proxy.EcdhSerialized(handshake.RemoteEphemeralPublicKey.Bytes, handshake.EphemeralPrivateKey.KeyBytes); byte[] nonceHash = Keccak.Compute(Bytes.Concat(handshake.RecipientNonce, handshake.InitiatorNonce)).Bytes; byte[] sharedSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, nonceHash)).Bytes; byte[] token = Keccak.Compute(sharedSecret).Bytes; byte[] aesSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, sharedSecret)).Bytes; Array.Clear(sharedSecret, 0, sharedSecret.Length); // TODO: it was passed in the concat for Keccak so not good enough byte[] macSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, aesSecret)).Bytes; Array.Clear(ephemeralSharedSecret, 0, ephemeralSharedSecret.Length); // TODO: it was passed in the concat for Keccak so not good enough handshake.Secrets = new EncryptionSecrets(); handshake.Secrets.Token = token; handshake.Secrets.AesSecret = aesSecret; handshake.Secrets.MacSecret = macSecret; KeccakDigest mac1 = new KeccakDigest(MacBitsSize); mac1.BlockUpdate(macSecret.Xor(handshake.RecipientNonce), 0, macSecret.Length); mac1.BlockUpdate(handshake.AuthPacket.Data, 0, handshake.AuthPacket.Data.Length); KeccakDigest mac2 = new KeccakDigest(MacBitsSize); mac2.BlockUpdate(macSecret.Xor(handshake.InitiatorNonce), 0, macSecret.Length); mac2.BlockUpdate(handshake.AckPacket.Data, 0, handshake.AckPacket.Data.Length); if (handshakeRole == HandshakeRole.Initiator) { handshake.Secrets.EgressMac = mac1; handshake.Secrets.IngressMac = mac2; } else { handshake.Secrets.EgressMac = mac2; handshake.Secrets.IngressMac = mac1; } if (_logger.IsTrace) { _logger.Trace($"Agreed secrets with {handshake.RemoteNodeId}"); } #if DEBUG if (_logger.IsTrace) { _logger.Trace($"{handshake.RemoteNodeId} ephemeral private key {handshake.EphemeralPrivateKey}"); _logger.Trace($"{handshake.RemoteNodeId} initiator nonce {handshake.InitiatorNonce.ToHexString()}"); _logger.Trace($"{handshake.RemoteNodeId} recipient nonce {handshake.RecipientNonce.ToHexString()}"); _logger.Trace($"{handshake.RemoteNodeId} remote ephemeral public key {handshake.RemoteEphemeralPublicKey}"); _logger.Trace($"{handshake.RemoteNodeId} remote public key {handshake.RemoteNodeId}"); _logger.Trace($"{handshake.RemoteNodeId} auth packet {handshake.AuthPacket.Data.ToHexString()}"); _logger.Trace($"{handshake.RemoteNodeId} ack packet {handshake.AckPacket.Data.ToHexString()}"); } #endif }
public void Agree(EncryptionHandshake handshake, Packet ack) { handshake.AckPacket = ack; bool isOld = false; byte[] plainText = null; try { (isOld, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data); } catch (Exception ex) { if (_logger.IsTrace) { _logger.Trace($"Exception when decrypting agree {ex.Message}"); } } if (isOld) { AckMessage ackMessage = _messageSerializationService.Deserialize <AckMessage>(plainText); if (_logger.IsTrace) { _logger.Trace("Received ACK old"); } handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey; handshake.RecipientNonce = ackMessage.Nonce; } else { byte[] sizeData = ack.Data.Slice(0, 2); (_, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data.Slice(2), sizeData); AckEip8Message ackEip8Message = _messageSerializationService.Deserialize <AckEip8Message>(plainText); if (_logger.IsTrace) { _logger.Trace($"Received ACK v{ackEip8Message.Version}"); } handshake.RemoteEphemeralPublicKey = ackEip8Message.EphemeralPublicKey; handshake.RecipientNonce = ackEip8Message.Nonce; } SetSecrets(handshake, HandshakeRole.Initiator); }
public static void SetSecrets(EncryptionHandshake handshake, HandshakeRole handshakeRole) { Span <byte> tempConcat = stackalloc byte[64]; Span <byte> ephemeralSharedSecret = Proxy.EcdhSerialized(handshake.RemoteEphemeralPublicKey.Bytes, handshake.EphemeralPrivateKey.KeyBytes); Span <byte> nonceHash = ValueKeccak.Compute(Bytes.Concat(handshake.RecipientNonce, handshake.InitiatorNonce)).BytesAsSpan; ephemeralSharedSecret.CopyTo(tempConcat.Slice(0, 32)); nonceHash.CopyTo(tempConcat.Slice(32, 32)); Span <byte> sharedSecret = ValueKeccak.Compute(tempConcat).BytesAsSpan; // byte[] token = Keccak.Compute(sharedSecret).Bytes; sharedSecret.CopyTo(tempConcat.Slice(32, 32)); byte[] aesSecret = Keccak.Compute(tempConcat).Bytes; sharedSecret.Clear(); aesSecret.CopyTo(tempConcat.Slice(32, 32)); byte[] macSecret = Keccak.Compute(tempConcat).Bytes; ephemeralSharedSecret.Clear(); handshake.Secrets = new EncryptionSecrets(); // handshake.Secrets.Token = token; handshake.Secrets.AesSecret = aesSecret; handshake.Secrets.MacSecret = macSecret; KeccakDigest mac1 = new KeccakDigest(MacBitsSize); mac1.BlockUpdate(macSecret.Xor(handshake.RecipientNonce), 0, macSecret.Length); mac1.BlockUpdate(handshake.AuthPacket.Data, 0, handshake.AuthPacket.Data.Length); KeccakDigest mac2 = new KeccakDigest(MacBitsSize); mac2.BlockUpdate(macSecret.Xor(handshake.InitiatorNonce), 0, macSecret.Length); mac2.BlockUpdate(handshake.AckPacket.Data, 0, handshake.AckPacket.Data.Length); if (handshakeRole == HandshakeRole.Initiator) { handshake.Secrets.EgressMac = mac1; handshake.Secrets.IngressMac = mac2; } else { handshake.Secrets.EgressMac = mac2; handshake.Secrets.IngressMac = mac1; } }
public static void SetSecrets(EncryptionHandshake handshake, HandshakeRole handshakeRole) { byte[] ephemeralSharedSecret = Proxy.EcdhSerialized(handshake.RemoteEphemeralPublicKey.Bytes, handshake.EphemeralPrivateKey.KeyBytes); byte[] nonceHash = Keccak.Compute(Bytes.Concat(handshake.RecipientNonce, handshake.InitiatorNonce)).Bytes; byte[] sharedSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, nonceHash)).Bytes; byte[] token = Keccak.Compute(sharedSecret).Bytes; byte[] aesSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, sharedSecret)).Bytes; Array.Clear(sharedSecret, 0, sharedSecret.Length); // TODO: it was passed in the concat for Keccak so not good enough byte[] macSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, aesSecret)).Bytes; Array.Clear(ephemeralSharedSecret, 0, ephemeralSharedSecret.Length); // TODO: it was passed in the concat for Keccak so not good enough handshake.Secrets = new EncryptionSecrets(); handshake.Secrets.Token = token; handshake.Secrets.AesSecret = aesSecret; handshake.Secrets.MacSecret = macSecret; KeccakDigest mac1 = new KeccakDigest(MacBitsSize); mac1.BlockUpdate(macSecret.Xor(handshake.RecipientNonce), 0, macSecret.Length); mac1.BlockUpdate(handshake.AuthPacket.Data, 0, handshake.AuthPacket.Data.Length); KeccakDigest mac2 = new KeccakDigest(MacBitsSize); mac2.BlockUpdate(macSecret.Xor(handshake.InitiatorNonce), 0, macSecret.Length); mac2.BlockUpdate(handshake.AckPacket.Data, 0, handshake.AckPacket.Data.Length); if (handshakeRole == HandshakeRole.Initiator) { handshake.Secrets.EgressMac = mac1; handshake.Secrets.IngressMac = mac2; } else { handshake.Secrets.EgressMac = mac2; handshake.Secrets.IngressMac = mac1; } }
public void Agree(EncryptionHandshake handshake, Packet ack) { handshake.AckPacket = ack; bool preEip8Format = false; byte[] plainText = null; try { (preEip8Format, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data); } catch (Exception ex) { if (_logger.IsTrace) { _logger.Trace($"Exception when decrypting agree {ex.Message}"); } } if (preEip8Format) { AckMessage ackMessage = _messageSerializationService.Deserialize <AckMessage>(plainText); if (_logger.IsTrace) { _logger.Trace("Received ACK old"); } handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey; handshake.RecipientNonce = ackMessage.Nonce; } else { byte[] sizeData = ack.Data.Slice(0, 2); (_, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data.Slice(2), sizeData); AckEip8Message ackEip8Message = _messageSerializationService.Deserialize <AckEip8Message>(plainText); if (_logger.IsTrace) { _logger.Trace($"Received ACK v{ackEip8Message.Version}"); } handshake.RemoteEphemeralPublicKey = ackEip8Message.EphemeralPublicKey; handshake.RecipientNonce = ackEip8Message.Nonce; } SetSecrets(handshake, HandshakeRole.Initiator); if (_logger.IsTrace) { _logger.Trace($"Agreed secrets with {handshake.RemoteNodeId}"); } #if DEBUG if (_logger.IsTrace) { _logger.Trace($"{handshake.RemoteNodeId} ephemeral private key {handshake.EphemeralPrivateKey}"); _logger.Trace($"{handshake.RemoteNodeId} initiator nonce {handshake.InitiatorNonce.ToHexString()}"); _logger.Trace($"{handshake.RemoteNodeId} recipient nonce {handshake.RecipientNonce.ToHexString()}"); _logger.Trace($"{handshake.RemoteNodeId} remote ephemeral public key {handshake.RemoteEphemeralPublicKey}"); _logger.Trace($"{handshake.RemoteNodeId} remote public key {handshake.RemoteNodeId}"); _logger.Trace($"{handshake.RemoteNodeId} auth packet {handshake.AuthPacket.Data.ToHexString()}"); _logger.Trace($"{handshake.RemoteNodeId} ack packet {handshake.AckPacket.Data.ToHexString()}"); } #endif }
public Packet Ack(EncryptionHandshake handshake, Packet auth) { handshake.AuthPacket = auth; AuthMessageBase authMessage; bool preEip8Format = false; byte[] plainText = null; try { if (_logger.IsTrace) { _logger.Trace($"Trying to decrypt an old version of {nameof(AuthMessage)}"); } (preEip8Format, plainText) = _eciesCipher.Decrypt(_privateKey, auth.Data); } catch (Exception ex) { if (_logger.IsTrace) { _logger.Trace($"Exception when decrypting ack {ex.Message}"); } } if (preEip8Format) { authMessage = _messageSerializationService.Deserialize <AuthMessage>(plainText); } else { if (_logger.IsTrace) { _logger.Trace($"Trying to decrypt version 4 of {nameof(AuthEip8Message)}"); } byte[] sizeData = auth.Data.Slice(0, 2); (_, plainText) = _eciesCipher.Decrypt(_privateKey, auth.Data.Slice(2), sizeData); authMessage = _messageSerializationService.Deserialize <AuthEip8Message>(plainText); } var nodeId = authMessage.PublicKey; if (_logger.IsTrace) { _logger.Trace($"Received AUTH v{authMessage.Version} from {nodeId}"); } handshake.RemoteNodeId = nodeId; handshake.RecipientNonce = _cryptoRandom.GenerateRandomBytes(32); handshake.EphemeralPrivateKey = _ephemeralGenerator.Generate(); handshake.InitiatorNonce = authMessage.Nonce; byte[] staticSharedSecret = Proxy.EcdhSerialized(handshake.RemoteNodeId.Bytes, _privateKey.KeyBytes); byte[] forSigning = staticSharedSecret.Xor(handshake.InitiatorNonce); handshake.RemoteEphemeralPublicKey = _ecdsa.RecoverPublicKey(authMessage.Signature, new Keccak(forSigning)); byte[] data; if (preEip8Format) { if (_logger.IsTrace) { _logger.Trace($"Building an {nameof(AckMessage)}"); } AckMessage ackMessage = new AckMessage(); ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey; ackMessage.Nonce = handshake.RecipientNonce; var ackData = _messageSerializationService.Serialize(ackMessage); data = _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData, Array.Empty <byte>()); } else { if (_logger.IsTrace) { _logger.Trace($"Building an {nameof(AckEip8Message)}"); } AckEip8Message ackMessage = new AckEip8Message(); ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey; ackMessage.Nonce = handshake.RecipientNonce; var ackData = _messageSerializationService.Serialize(ackMessage); int size = ackData.Length + 32 + 16 + 65; // data + MAC + IV + pub byte[] sizeBytes = size.ToBigEndianByteArray().Slice(2, 2); data = Bytes.Concat(sizeBytes, _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData, sizeBytes)); } handshake.AckPacket = new Packet(data); SetSecrets(handshake, HandshakeRole.Recipient); return(handshake.AckPacket); }
public Packet Ack(EncryptionHandshake handshake, Packet auth) { handshake.AuthPacket = auth; AuthMessageBase authMessage; bool isOld = false; try { _logger.Info($"Trying to decrypt an old version of {nameof(AuthMessage)}"); byte[] plaintextOld = _eciesCipher.Decrypt(_privateKey, auth.Data); authMessage = _messageSerializationService.Deserialize <AuthMessage>(plaintextOld); isOld = true; } catch (Exception) { _logger.Info($"Trying to decrypt version 4 of {nameof(AuthEip8Message)}"); byte[] sizeData = auth.Data.Slice(0, 2); byte[] plaintext = _eciesCipher.Decrypt(_privateKey, auth.Data.Slice(2), sizeData); authMessage = _messageSerializationService.Deserialize <AuthEip8Message>(plaintext); } var nodeId = new NodeId(authMessage.PublicKey); _logger.Debug($"Received AUTH v{authMessage.Version} from {nodeId}"); handshake.RemoteNodeId = nodeId; handshake.RecipientNonce = _cryptoRandom.GenerateRandomBytes(32); handshake.EphemeralPrivateKey = new PrivateKey(_cryptoRandom.GenerateRandomBytes(32)); handshake.InitiatorNonce = authMessage.Nonce; byte[] staticSharedSecret = BouncyCrypto.Agree(_privateKey, handshake.RemoteNodeId.PublicKey); byte[] forSigning = staticSharedSecret.Xor(handshake.InitiatorNonce); handshake.RemoteEphemeralPublicKey = _signer.RecoverPublicKey(authMessage.Signature, new Keccak(forSigning)); byte[] ackData; if (isOld) // what was the difference? shall I really include ephemeral public key in v4? { _logger.Debug($"Building an {nameof(AckMessage)}"); AckMessage ackMessage = new AckMessage(); ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey; ackMessage.Nonce = handshake.RecipientNonce; ackData = _messageSerializationService.Serialize(ackMessage); } else { _logger.Debug($"Building an {nameof(AckEip8Message)}"); AckEip8Message ackMessage = new AckEip8Message(); ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey; ackMessage.Nonce = handshake.RecipientNonce; ackData = _messageSerializationService.Serialize(ackMessage); } int size = ackData.Length + 32 + 16 + 65; // data + MAC + IV + pub byte[] sizeBytes = size.ToBigEndianByteArray().Slice(2, 2); byte[] packetData = _eciesCipher.Encrypt(handshake.RemoteNodeId.PublicKey, ackData, sizeBytes); handshake.AckPacket = new Packet(Bytes.Concat(sizeBytes, packetData)); SetSecrets(handshake, EncryptionHandshakeRole.Recipient); return(handshake.AckPacket); }